asciidoctor-pdf 1.6.1 → 2.0.0.alpha.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +1 -1
- data/CHANGELOG.adoc +273 -31
- data/NOTICE.adoc +16 -4
- data/README.adoc +208 -68
- data/asciidoctor-pdf.gemspec +3 -7
- data/data/fonts/ABOUT-mplus1mn-subset +1 -1
- data/data/fonts/ABOUT-mplus1p-subset +2 -2
- data/data/fonts/ABOUT-notosans-subset +26 -0
- data/data/fonts/ABOUT-notoserif-subset +1 -1
- data/data/fonts/{LICENSE-notoserif → LICENSE-noto} +0 -0
- data/data/fonts/mplus1mn-bold-subset.ttf +0 -0
- data/data/fonts/mplus1mn-bold_italic-subset.ttf +0 -0
- data/data/fonts/mplus1mn-italic-subset.ttf +0 -0
- data/data/fonts/mplus1mn-regular-subset.ttf +0 -0
- data/data/fonts/mplus1p-regular-fallback.ttf +0 -0
- data/data/fonts/notoemoji-subset.ttf +0 -0
- data/data/fonts/notosans-bold-subset.ttf +0 -0
- data/data/fonts/notosans-bold_italic-subset.ttf +0 -0
- data/data/fonts/notosans-italic-subset.ttf +0 -0
- data/data/fonts/notosans-regular-subset.ttf +0 -0
- data/data/fonts/notoserif-bold-subset.ttf +0 -0
- data/data/fonts/notoserif-bold_italic-subset.ttf +0 -0
- data/data/fonts/notoserif-italic-subset.ttf +0 -0
- data/data/fonts/notoserif-regular-subset.ttf +0 -0
- data/data/themes/base-theme.yml +21 -24
- data/data/themes/default-for-print-theme.yml +24 -0
- data/data/themes/default-for-print-with-fallback-font-theme.yml +3 -0
- data/data/themes/default-theme.yml +55 -59
- data/data/themes/default-with-fallback-font-theme.yml +2 -2
- data/data/themes/sans-with-fallback-font-theme.yml +10 -0
- data/docs/theming-guide.adoc +977 -352
- data/lib/asciidoctor/pdf/converter.rb +1853 -1566
- data/lib/asciidoctor/pdf/ext/asciidoctor/document.rb +22 -1
- data/lib/asciidoctor/pdf/ext/asciidoctor/image.rb +9 -15
- data/lib/asciidoctor/pdf/ext/asciidoctor/list.rb +6 -13
- data/lib/asciidoctor/pdf/ext/asciidoctor/section.rb +3 -16
- data/lib/asciidoctor/pdf/ext/asciidoctor.rb +1 -5
- data/lib/asciidoctor/pdf/ext/core/file.rb +1 -1
- data/lib/asciidoctor/pdf/ext/core/quantifiable_stdout.rb +1 -4
- data/lib/asciidoctor/pdf/ext/core/string.rb +2 -2
- data/lib/asciidoctor/pdf/ext/core.rb +1 -4
- data/lib/asciidoctor/pdf/ext/pdf-core/page.rb +8 -33
- data/lib/asciidoctor/pdf/ext/pdf-core.rb +0 -16
- data/lib/asciidoctor/pdf/ext/prawn/coderay_encoder.rb +5 -7
- data/lib/asciidoctor/pdf/ext/prawn/extensions.rb +489 -331
- data/lib/asciidoctor/pdf/ext/prawn/font/afm.rb +0 -4
- data/lib/asciidoctor/pdf/ext/prawn/font_metric_cache.rb +1 -1
- data/lib/asciidoctor/pdf/ext/prawn/formatted_text/arranger.rb +33 -3
- data/lib/asciidoctor/pdf/ext/prawn/formatted_text/box.rb +25 -14
- data/lib/asciidoctor/pdf/ext/prawn/formatted_text/fragment.rb +9 -3
- data/lib/asciidoctor/pdf/ext/prawn/formatted_text/protect_bottom_gutter.rb +13 -0
- data/lib/asciidoctor/pdf/ext/prawn/images.rb +20 -18
- data/lib/asciidoctor/pdf/ext/prawn-svg/loaders/data.rb +6 -0
- data/lib/asciidoctor/pdf/ext/prawn-svg/loaders/web.rb +22 -0
- data/lib/asciidoctor/pdf/ext/prawn-svg/url_loader.rb +13 -0
- data/lib/asciidoctor/pdf/ext/prawn-svg.rb +5 -2
- data/lib/asciidoctor/pdf/ext/prawn-table/cell/asciidoc.rb +76 -20
- data/lib/asciidoctor/pdf/ext/prawn-table/cell/text.rb +39 -1
- data/lib/asciidoctor/pdf/ext/prawn-table/cell.rb +21 -15
- data/lib/asciidoctor/pdf/ext/prawn-table.rb +1 -1
- data/lib/asciidoctor/pdf/ext/prawn.rb +1 -0
- data/lib/asciidoctor/pdf/ext/pygments.rb +2 -2
- data/lib/asciidoctor/pdf/ext/rouge/formatters/prawn.rb +17 -20
- data/lib/asciidoctor/pdf/ext/rouge/themes/asciidoctor_pdf_default.rb +1 -0
- data/lib/asciidoctor/pdf/ext/rouge.rb +0 -1
- data/lib/asciidoctor/pdf/formatted_text/formatter.rb +2 -2
- data/lib/asciidoctor/pdf/formatted_text/inline_destination_marker.rb +8 -10
- data/lib/asciidoctor/pdf/formatted_text/inline_image_arranger.rb +69 -78
- data/lib/asciidoctor/pdf/formatted_text/inline_image_renderer.rb +7 -10
- data/lib/asciidoctor/pdf/formatted_text/inline_text_aligner.rb +2 -4
- data/lib/asciidoctor/pdf/formatted_text/parser.rb +53 -47
- data/lib/asciidoctor/pdf/formatted_text/parser.treetop +5 -7
- data/lib/asciidoctor/pdf/formatted_text/source_wrap.rb +14 -14
- data/lib/asciidoctor/pdf/formatted_text/text_background_and_border_renderer.rb +4 -7
- data/lib/asciidoctor/pdf/formatted_text/transform.rb +122 -110
- data/lib/asciidoctor/pdf/formatted_text.rb +0 -1
- data/lib/asciidoctor/pdf/index_catalog.rb +7 -11
- data/lib/asciidoctor/pdf/nogmagick.rb +6 -0
- data/lib/asciidoctor/pdf/optimizer.rb +3 -5
- data/lib/asciidoctor/pdf/pdfmark.rb +16 -8
- data/lib/asciidoctor/pdf/roman_numeral.rb +4 -22
- data/lib/asciidoctor/pdf/sanitizer.rb +18 -13
- data/lib/asciidoctor/pdf/section_info_by_page.rb +24 -0
- data/lib/asciidoctor/pdf/theme_loader.rb +100 -80
- data/lib/asciidoctor/pdf/version.rb +1 -2
- data/lib/asciidoctor/pdf.rb +5 -2
- metadata +36 -64
- data/data/fonts/mplus1mn-bold-ascii.ttf +0 -0
- data/data/fonts/mplus1mn-bold_italic-ascii.ttf +0 -0
- data/data/fonts/mplus1mn-italic-ascii.ttf +0 -0
- data/data/fonts/mplus1mn-regular-ascii-conums.ttf +0 -0
- data/lib/asciidoctor/pdf/ext/asciidoctor/abstract_block.rb +0 -7
- data/lib/asciidoctor/pdf/ext/asciidoctor/abstract_node.rb +0 -7
- data/lib/asciidoctor/pdf/ext/asciidoctor/list_item.rb +0 -18
- data/lib/asciidoctor/pdf/ext/asciidoctor/logging_shim.rb +0 -33
- data/lib/asciidoctor/pdf/ext/core/array.rb +0 -11
- data/lib/asciidoctor/pdf/ext/core/hash.rb +0 -7
- data/lib/asciidoctor/pdf/ext/core/regexp.rb +0 -5
- data/lib/asciidoctor/pdf/ext/pdf-core/pdf_object.rb +0 -8
- data/lib/asciidoctor-pdf/converter.rb +0 -3
- data/lib/asciidoctor-pdf/version.rb +0 -3
@@ -28,7 +28,7 @@ module Rouge
|
|
28
28
|
|
29
29
|
def initialize opts = {}
|
30
30
|
unless ::Rouge::Theme === (theme = opts[:theme])
|
31
|
-
unless theme && (theme = ::Rouge::Theme.find theme)
|
31
|
+
unless theme && ((::Class === theme && theme < ::Rouge::Theme) || (theme = ::Rouge::Theme.find theme))
|
32
32
|
theme = ::Rouge::Themes::AsciidoctorPDFDefault
|
33
33
|
end
|
34
34
|
theme = theme.new
|
@@ -41,13 +41,7 @@ module Rouge
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def background_color
|
44
|
-
@background_color ||= (normalize_color (@theme.style_for Tokens::Text).bg)
|
45
|
-
end
|
46
|
-
|
47
|
-
# Override format method so fragments don't get flatted to a string
|
48
|
-
# and to add an options Hash.
|
49
|
-
def format tokens, opts = {}
|
50
|
-
stream tokens, opts
|
44
|
+
@background_color ||= (normalize_color ((@theme.style_for Tokens::Text) || (::Rouge::Theme::Style.new @theme)).bg)
|
51
45
|
end
|
52
46
|
|
53
47
|
def stream tokens, opts = {}
|
@@ -65,7 +59,7 @@ module Rouge
|
|
65
59
|
line_numbers ? (fragments << (create_linenum_fragment linenum)) : (start_of_line = true)
|
66
60
|
fragments << @highlight_line_fragment.dup if highlight_lines && highlight_lines[linenum]
|
67
61
|
elsif val.include? LF
|
68
|
-
# NOTE we assume if the fragment ends in a line feed, the intention was to match a line-oriented form
|
62
|
+
# NOTE: we assume if the fragment ends in a line feed, the intention was to match a line-oriented form
|
69
63
|
line_oriented = val.end_with? LF
|
70
64
|
base_fragment = create_fragment tok, val
|
71
65
|
val.each_line do |line|
|
@@ -75,7 +69,7 @@ module Rouge
|
|
75
69
|
end
|
76
70
|
fragments << (line_oriented ? (base_fragment.merge text: line, inline_block: true) : (base_fragment.merge text: line))
|
77
71
|
next unless line.end_with? LF
|
78
|
-
# NOTE eagerly append linenum fragment or line highlight if there's a next line
|
72
|
+
# NOTE: eagerly append linenum fragment or line highlight if there's a next line
|
79
73
|
linenum += 1
|
80
74
|
line_numbers ? (fragments << (create_linenum_fragment linenum)) : (start_of_line = true)
|
81
75
|
fragments << @highlight_line_fragment.dup if highlight_lines && highlight_lines[linenum]
|
@@ -88,10 +82,10 @@ module Rouge
|
|
88
82
|
fragments << (create_fragment tok, val)
|
89
83
|
end
|
90
84
|
end
|
91
|
-
# NOTE pad numbers that have less digits than the largest line number
|
92
|
-
# FIXME we could store these fragments so we don't have find them again
|
85
|
+
# NOTE: pad numbers that have less digits than the largest line number
|
86
|
+
# FIXME: we could store these fragments so we don't have find them again
|
93
87
|
if line_numbers && (linenum_w = linenum.to_s.length) > 1
|
94
|
-
# NOTE extra column is the trailing space after the line number
|
88
|
+
# NOTE: extra column is the trailing space after the line number
|
95
89
|
linenum_w += 1
|
96
90
|
fragments.each do |fragment|
|
97
91
|
fragment[:text] = (fragment[:text].rjust linenum_w, NoBreakSpace).to_s if fragment[:linenum]
|
@@ -108,10 +102,10 @@ module Rouge
|
|
108
102
|
else
|
109
103
|
val[0] = GuardedIndent if start_of_line && (val.start_with? ' ')
|
110
104
|
val.gsub! InnerIndent, GuardedInnerIndent if val.include? InnerIndent
|
111
|
-
# QUESTION do we need the call to create_fragment if val contains only spaces? consider bg
|
105
|
+
# QUESTION: do we need the call to create_fragment if val contains only spaces? consider bg
|
112
106
|
#fragment = create_fragment tok, val
|
113
107
|
fragment = val.rstrip.empty? ? { text: val } : (create_fragment tok, val)
|
114
|
-
# NOTE we assume if the fragment ends in a line feed, the intention was to match a line-oriented form
|
108
|
+
# NOTE: we assume if the fragment ends in a line feed, the intention was to match a line-oriented form
|
115
109
|
fragment[:inline_block] = true if (start_of_line = val.end_with? LF)
|
116
110
|
fragment
|
117
111
|
end
|
@@ -119,6 +113,10 @@ module Rouge
|
|
119
113
|
end
|
120
114
|
end
|
121
115
|
|
116
|
+
# Override format method so fragments don't get flatted to a string
|
117
|
+
# and to add an options Hash.
|
118
|
+
alias format stream
|
119
|
+
|
122
120
|
# TODO: method could still be optimized (for instance, check if val is LF or empty)
|
123
121
|
def create_fragment tok, val = nil
|
124
122
|
fragment = val ? { text: val } : {}
|
@@ -144,7 +142,7 @@ module Rouge
|
|
144
142
|
end
|
145
143
|
if style_rules[:underline]
|
146
144
|
if fragment.key? :styles
|
147
|
-
fragment[:styles]
|
145
|
+
fragment[:styles] |= UnderlineStyle
|
148
146
|
else
|
149
147
|
fragment[:styles] = UnderlineStyle.dup
|
150
148
|
end
|
@@ -174,9 +172,8 @@ module Rouge
|
|
174
172
|
if (normalized = @normalized_colors[raw])
|
175
173
|
normalized
|
176
174
|
else
|
177
|
-
normalized =
|
178
|
-
|
179
|
-
@normalized_colors[raw] = normalized
|
175
|
+
normalized = raw.slice 1, raw.length
|
176
|
+
@normalized_colors[raw] = normalized.length == 3 ? normalized.each_char.map {|c| c * 2 }.join : normalized
|
180
177
|
end
|
181
178
|
end
|
182
179
|
|
@@ -199,7 +196,7 @@ module Rouge
|
|
199
196
|
end
|
200
197
|
pdf.fill_rectangle [fragment.left, fragment.top + v_gap * 0.5], fragment_width, (fragment.height + v_gap)
|
201
198
|
pdf.fill_color prev_fill_color
|
202
|
-
fragment.conceal if fragment.text == DummyText
|
199
|
+
fragment.conceal true if fragment.text == DummyText
|
203
200
|
nil
|
204
201
|
end
|
205
202
|
end
|
@@ -10,6 +10,7 @@ module Rouge
|
|
10
10
|
# Deviate from pastie here since our italic is actually a thinner font
|
11
11
|
style Comment, fg: '#888888' #, italic: true
|
12
12
|
style Comment::Preproc, fg: '#cc0000', bold: true
|
13
|
+
style Comment::PreprocFile, fg: '#cc0000', bold: true if defined? Comment::PreprocFile
|
13
14
|
# Deviate from pastie here by not using a background color
|
14
15
|
style Comment::Special, fg: '#cc0000', bold: true #, bg: '#fff0f0'
|
15
16
|
|
@@ -24,9 +24,9 @@ module Asciidoctor
|
|
24
24
|
if FormattingSnifferPattern.match? string
|
25
25
|
if (parsed = @parser.parse string)
|
26
26
|
return @transform.apply parsed.content, [], inherited
|
27
|
-
elsif !@scratch
|
28
|
-
logger.error %(failed to parse formatted text: #{string})
|
29
27
|
end
|
28
|
+
reason = @parser.failure_reason.sub %r/ at line \d+, column \d+ \(byte (\d+)\)(.*)/, '\2 at byte \1'
|
29
|
+
logger.error %(failed to parse formatted text: #{string} (reason: #{reason})) unless @scratch
|
30
30
|
end
|
31
31
|
[inherited ? (inherited.merge text: string) : { text: string }]
|
32
32
|
end
|
@@ -6,16 +6,14 @@ module Asciidoctor::PDF::FormattedText
|
|
6
6
|
|
7
7
|
# render_behind is called before the text is printed
|
8
8
|
def render_behind fragment
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
18
|
-
end
|
9
|
+
return if (pdf = fragment.document).scratch?
|
10
|
+
name = fragment.format_state[:name]
|
11
|
+
pdf.index.link_dest_to_page name, pdf.page_number if fragment.format_state[:type] == :indexterm
|
12
|
+
# get precise position of the reference (x, y)
|
13
|
+
dest_rect = fragment.absolute_bounding_box
|
14
|
+
pdf.add_dest name, (pdf.dest_xyz dest_rect[0], dest_rect[-1])
|
15
|
+
# prevent any text from being written
|
16
|
+
fragment.conceal true
|
19
17
|
end
|
20
18
|
end
|
21
19
|
end
|
@@ -37,7 +37,7 @@ module Asciidoctor::PDF::FormattedText
|
|
37
37
|
doc = @document
|
38
38
|
return if (raw_image_fragments = fragments.select {|f| (f.key? :image_path) && !(f.key? :image_obj) }).empty?
|
39
39
|
scratch = doc.scratch?
|
40
|
-
available_w =
|
40
|
+
available_w = available_width
|
41
41
|
available_h = doc.page.empty? ? doc.cursor : doc.bounds.height
|
42
42
|
last_fragment = {}
|
43
43
|
raw_image_fragments.each do |fragment|
|
@@ -47,92 +47,83 @@ module Asciidoctor::PDF::FormattedText
|
|
47
47
|
else
|
48
48
|
drop = scratch
|
49
49
|
end
|
50
|
-
|
51
|
-
|
50
|
+
image_path = fragment[:image_path]
|
51
|
+
image_w = fragment[:image_width] || '100%'
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
# NOTE: intrinsic width is stored behind % symbol
|
54
|
+
if (pctidx = image_w.index '%') && pctidx + 1 < image_w.length
|
55
|
+
pct = (image_w.slice 0, pctidx).to_f / 100
|
56
|
+
intrinsic_w = (image_w.slice pctidx + 1, image_w.length).to_f
|
57
|
+
image_w = [available_w, pct * intrinsic_w].min
|
58
|
+
else
|
59
|
+
image_w = [available_w, pctidx ? (image_w.to_f / 100 * available_w) : image_w.to_f].min
|
60
|
+
end
|
57
61
|
|
58
|
-
|
62
|
+
max_image_h = fragment[:image_fit] == 'line' ? [available_h, doc.font.height].min : available_h
|
59
63
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
if (image_h = svg_size.output_height) > max_image_h
|
74
|
-
image_w = (svg_obj.resize height: (image_h = max_image_h)).output_width
|
75
|
-
else
|
76
|
-
image_w = svg_size.output_width
|
77
|
-
end
|
78
|
-
fragment[:image_obj] = svg_obj
|
64
|
+
# TODO: make helper method to calculate width and height of image
|
65
|
+
if fragment[:image_format] == 'svg'
|
66
|
+
svg_obj = ::Prawn::SVG::Interface.new ::File.read(image_path, mode: 'r:UTF-8'), doc,
|
67
|
+
at: doc.bounds.top_left,
|
68
|
+
width: image_w,
|
69
|
+
fallback_font_name: doc.fallback_svg_font_name,
|
70
|
+
enable_web_requests: doc.allow_uri_read ? (doc.method :load_open_uri).to_proc : false,
|
71
|
+
enable_file_requests_with_root: (::File.dirname image_path),
|
72
|
+
cache_images: doc.cache_uri
|
73
|
+
svg_size = svg_obj.document.sizing
|
74
|
+
# NOTE: the best we can do is make the image fit within full height of bounds
|
75
|
+
if (image_h = svg_size.output_height) > max_image_h
|
76
|
+
image_w = (svg_obj.resize height: (image_h = max_image_h)).output_width
|
79
77
|
else
|
80
|
-
|
81
|
-
# NOTE image_obj is constrained to image_width by renderer
|
82
|
-
image_obj, image_info = ::File.open(image_path, 'rb') {|fd| doc.build_image_object fd }
|
83
|
-
if image_w
|
84
|
-
if image_w == image_info.width
|
85
|
-
image_h = image_info.height.to_f
|
86
|
-
else
|
87
|
-
image_h = image_w * (image_info.height.fdiv image_info.width)
|
88
|
-
end
|
89
|
-
# NOTE convert intrinsic dimensions to points; constrain to content width
|
90
|
-
elsif (image_w = to_pt image_info.width, :px) > available_w
|
91
|
-
image_h = (image_w = available_w) * (image_info.height.fdiv image_info.width)
|
92
|
-
else
|
93
|
-
image_h = to_pt image_info.height, :px
|
94
|
-
end
|
95
|
-
# NOTE the best we can do is make the image fit within full height of bounds
|
96
|
-
image_w = (image_h = max_image_h) * (image_info.width.fdiv image_info.height) if image_h > max_image_h
|
97
|
-
fragment[:image_obj] = image_obj
|
98
|
-
fragment[:image_info] = image_info
|
78
|
+
image_w = svg_size.output_width
|
99
79
|
end
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
# align with baseline (roughly equivalent to vertical-align: baseline in CSS)
|
109
|
-
#fragment[:ascender] = f_height
|
110
|
-
#fragment[:descender] = 0
|
111
|
-
#doc.font_size(fragment[:size] = (f_height + line_font.descender) * (doc.font_size / line_font.height))
|
112
|
-
fragment[:line_height_increased] = true
|
113
|
-
end
|
80
|
+
fragment[:image_obj] = svg_obj
|
81
|
+
else
|
82
|
+
# TODO: cache image info based on path (Prawn caches based on SHA1 of content)
|
83
|
+
# NOTE: image_obj is constrained to image_width by renderer
|
84
|
+
image_obj, image_info = ::File.open(image_path, 'rb') {|fd| doc.build_image_object fd }
|
85
|
+
if (image_h = image_w * (image_info.height.fdiv image_info.width)) > max_image_h
|
86
|
+
# NOTE: the best we can do is make the image fit within full height of bounds
|
87
|
+
image_w = (image_h = max_image_h) * (image_info.width.fdiv image_info.height)
|
114
88
|
end
|
89
|
+
fragment[:image_obj] = image_obj
|
90
|
+
fragment[:image_info] = image_info
|
91
|
+
end
|
115
92
|
|
116
|
-
|
117
|
-
#
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
if drop
|
129
|
-
fragment.delete :callback
|
130
|
-
fragment.delete :image_info
|
131
|
-
# NOTE retain key to indicate we've visited fragment already
|
132
|
-
fragment[:image_obj] = nil
|
93
|
+
doc.save_font do
|
94
|
+
# NOTE: if image height exceeds line height by more than 1.5x, increase the line height
|
95
|
+
# FIXME: we could really use a nicer API from Prawn here; this is an ugly hack
|
96
|
+
if (f_height = image_h) > (line_font = doc.font).height * 1.5
|
97
|
+
# align with descender (equivalent to vertical-align: bottom in CSS)
|
98
|
+
fragment[:ascender] = f_height - (fragment[:descender] = line_font.descender)
|
99
|
+
doc.font_size (fragment[:size] = f_height * (doc.font_size / line_font.height))
|
100
|
+
# align with baseline (roughly equivalent to vertical-align: baseline in CSS)
|
101
|
+
#fragment[:ascender] = f_height
|
102
|
+
#fragment[:descender] = 0
|
103
|
+
#doc.font_size(fragment[:size] = (f_height + line_font.descender) * (doc.font_size / line_font.height))
|
104
|
+
fragment[:line_height_increased] = true
|
133
105
|
end
|
134
|
-
last_fragment = fragment
|
135
106
|
end
|
107
|
+
|
108
|
+
# NOTE: we can't rely on the fragment width because the line wrap mechanism ignores it;
|
109
|
+
# it only considers the text (string) and character spacing, rebuilding the string several times
|
110
|
+
fragment[:text] = PlaceholderChar
|
111
|
+
fragment[:actual_character_spacing] = doc.character_spacing
|
112
|
+
fragment[:character_spacing] = image_w
|
113
|
+
fragment[:image_width] = fragment[:width] = image_w
|
114
|
+
fragment[:image_height] = image_h
|
115
|
+
rescue
|
116
|
+
logger.warn %(could not embed image: #{image_path}; #{$!.message}#{::Prawn::Errors::UnsupportedImageType === $! && !(defined? ::GMagick::Image) ? '; install prawn-gmagick gem to add support' : ''}) unless scratch
|
117
|
+
drop = true # delegate to cleanup logic in ensure block
|
118
|
+
ensure
|
119
|
+
# NOTE: skip rendering image in scratch document or if image can't be loaded
|
120
|
+
if drop
|
121
|
+
fragment.delete :callback
|
122
|
+
fragment.delete :image_info
|
123
|
+
# NOTE: retain key to indicate we've visited fragment already
|
124
|
+
fragment[:image_obj] = nil
|
125
|
+
end
|
126
|
+
last_fragment = fragment
|
136
127
|
end
|
137
128
|
end
|
138
129
|
end
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
module Asciidoctor::PDF::FormattedText
|
4
4
|
module InlineImageRenderer
|
5
|
+
include ::Asciidoctor::Logging
|
6
|
+
|
5
7
|
module_function
|
6
8
|
|
7
9
|
# Embeds the image object in this fragment into the document in place of the
|
@@ -26,20 +28,15 @@ module Asciidoctor::PDF::FormattedText
|
|
26
28
|
image_top = fragment.top - ((fragment.height - data[:image_height]) / 2.0)
|
27
29
|
end
|
28
30
|
image_left = fragment.left + ((fragment.width - data[:image_width]) / 2.0)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
# NOTE prawn-svg messes with the cursor; use float to workaround
|
33
|
-
# NOTE prawn-svg 0.24.0, 0.25.0, & 0.25.1 didn't restore font after call to draw (see mogest/prawn-svg#80)
|
31
|
+
if Prawn::SVG::Interface === (image_obj = data[:image_obj])
|
32
|
+
image_obj.options[:at] = [image_left, image_top]
|
33
|
+
# NOTE: prawn-svg messes with the cursor; use float to workaround
|
34
34
|
pdf.float do
|
35
35
|
pdf.character_spacing(data[:actual_character_spacing]) { image_obj.draw }
|
36
|
-
image_obj.document.warnings.each
|
37
|
-
# NOTE shim logger can't be imported into a module, so use the one from the PDF document instead
|
38
|
-
pdf.logger.warn %(problem encountered in image: #{data[:image_path]}; #{img_warning})
|
39
|
-
end
|
36
|
+
image_obj.document.warnings.each {|img_warning| logger.warn %(problem encountered in image: #{data[:image_path]}; #{img_warning}) }
|
40
37
|
end
|
41
38
|
else
|
42
|
-
pdf.embed_image
|
39
|
+
pdf.embed_image image_obj, data[:image_info], at: [image_left, image_top], width: data[:image_width], height: data[:image_height]
|
43
40
|
end
|
44
41
|
# ...or use the public interface, loading the image again
|
45
42
|
#pdf.image data[:image_path], at: [image_left, image_top], width: data[:image_width]
|
@@ -10,10 +10,8 @@ module Asciidoctor::PDF::FormattedText
|
|
10
10
|
x = fragment.left
|
11
11
|
y = fragment.baseline
|
12
12
|
align = fragment.format_state[:align]
|
13
|
-
if align == :center || align == :right
|
14
|
-
|
15
|
-
x += gap_width * (align == :center ? 0.5 : 1)
|
16
|
-
end
|
13
|
+
if (align == :center || align == :right) && (gap_width = fragment.width - (document.width_of text)) != 0
|
14
|
+
x += gap_width * (align == :center ? 0.5 : 1)
|
17
15
|
end
|
18
16
|
document.draw_text! text, at: [x, y]
|
19
17
|
fragment.conceal
|