asciidoctor-pdf 1.5.0.beta.8 → 1.5.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +49 -0
  3. data/LICENSE.adoc +1 -1
  4. data/NOTICE.adoc +1 -1
  5. data/README.adoc +43 -47
  6. data/asciidoctor-pdf.gemspec +5 -1
  7. data/bin/asciidoctor-pdf-optimize +1 -1
  8. data/data/themes/base-theme.yml +4 -3
  9. data/data/themes/default-theme.yml +10 -5
  10. data/docs/theming-guide.adoc +286 -22
  11. data/lib/asciidoctor-pdf.rb +1 -0
  12. data/lib/asciidoctor-pdf/converter.rb +1 -0
  13. data/lib/asciidoctor-pdf/version.rb +1 -0
  14. data/lib/asciidoctor/pdf.rb +13 -2
  15. data/lib/asciidoctor/pdf/converter.rb +3962 -3955
  16. data/lib/asciidoctor/pdf/ext.rb +9 -0
  17. data/lib/asciidoctor/pdf/ext/asciidoctor.rb +1 -0
  18. data/lib/asciidoctor/pdf/ext/asciidoctor/abstract_block.rb +1 -0
  19. data/lib/asciidoctor/pdf/ext/asciidoctor/abstract_node.rb +1 -0
  20. data/lib/asciidoctor/pdf/ext/asciidoctor/document.rb +1 -0
  21. data/lib/asciidoctor/pdf/ext/asciidoctor/image.rb +18 -16
  22. data/lib/asciidoctor/pdf/ext/asciidoctor/list.rb +3 -2
  23. data/lib/asciidoctor/pdf/ext/asciidoctor/list_item.rb +2 -1
  24. data/lib/asciidoctor/pdf/ext/asciidoctor/logging_shim.rb +3 -4
  25. data/lib/asciidoctor/pdf/ext/asciidoctor/section.rb +8 -6
  26. data/lib/asciidoctor/pdf/ext/core.rb +2 -0
  27. data/lib/asciidoctor/pdf/ext/core/array.rb +1 -0
  28. data/lib/asciidoctor/pdf/ext/core/hash.rb +1 -0
  29. data/lib/asciidoctor/pdf/ext/core/numeric.rb +4 -3
  30. data/lib/asciidoctor/pdf/ext/core/object.rb +1 -0
  31. data/lib/asciidoctor/pdf/ext/core/quantifiable_stdout.rb +8 -1
  32. data/lib/asciidoctor/pdf/ext/core/regexp.rb +1 -0
  33. data/lib/asciidoctor/pdf/ext/core/string.rb +6 -7
  34. data/lib/asciidoctor/pdf/ext/pdf-core.rb +1 -0
  35. data/lib/asciidoctor/pdf/ext/pdf-core/page.rb +3 -4
  36. data/lib/asciidoctor/pdf/ext/pdf-core/pdf_object.rb +2 -1
  37. data/lib/asciidoctor/pdf/ext/prawn-svg.rb +1 -0
  38. data/lib/asciidoctor/pdf/ext/prawn-svg/interface.rb +11 -8
  39. data/lib/asciidoctor/pdf/ext/prawn-table.rb +2 -1
  40. data/lib/asciidoctor/pdf/ext/prawn-table/cell.rb +9 -10
  41. data/lib/asciidoctor/pdf/ext/prawn-table/cell/asciidoc.rb +62 -57
  42. data/lib/asciidoctor/pdf/ext/prawn-table/cell/text.rb +5 -3
  43. data/lib/asciidoctor/pdf/ext/prawn-templates.rb +1 -0
  44. data/lib/asciidoctor/pdf/ext/prawn.rb +1 -0
  45. data/lib/asciidoctor/pdf/ext/prawn/coderay_encoder.rb +73 -72
  46. data/lib/asciidoctor/pdf/ext/prawn/extensions.rb +814 -818
  47. data/lib/asciidoctor/pdf/ext/prawn/font/afm.rb +4 -3
  48. data/lib/asciidoctor/pdf/ext/prawn/formatted_text/box.rb +2 -1
  49. data/lib/asciidoctor/pdf/ext/prawn/formatted_text/fragment.rb +7 -2
  50. data/lib/asciidoctor/pdf/ext/prawn/images.rb +45 -44
  51. data/lib/asciidoctor/pdf/ext/pygments.rb +34 -0
  52. data/lib/asciidoctor/pdf/ext/rouge.rb +1 -1
  53. data/lib/asciidoctor/pdf/ext/rouge/formatters/prawn.rb +181 -149
  54. data/lib/asciidoctor/pdf/ext/rouge/themes/asciidoctor_pdf_default.rb +1 -0
  55. data/lib/asciidoctor/pdf/formatted_text.rb +2 -0
  56. data/lib/asciidoctor/pdf/formatted_text/formatter.rb +35 -34
  57. data/lib/asciidoctor/pdf/formatted_text/fragment_position_renderer.rb +8 -7
  58. data/lib/asciidoctor/pdf/formatted_text/inline_destination_marker.rb +13 -14
  59. data/lib/asciidoctor/pdf/formatted_text/inline_image_arranger.rb +112 -133
  60. data/lib/asciidoctor/pdf/formatted_text/inline_image_renderer.rb +43 -41
  61. data/lib/asciidoctor/pdf/formatted_text/inline_text_aligner.rb +15 -14
  62. data/lib/asciidoctor/pdf/formatted_text/source_wrap.rb +43 -0
  63. data/lib/asciidoctor/pdf/formatted_text/text_background_and_border_renderer.rb +46 -37
  64. data/lib/asciidoctor/pdf/formatted_text/transform.rb +371 -352
  65. data/lib/asciidoctor/pdf/index_catalog.rb +99 -95
  66. data/lib/asciidoctor/pdf/measurements.rb +51 -48
  67. data/lib/asciidoctor/pdf/optimizer.rb +34 -31
  68. data/lib/asciidoctor/pdf/pdfmark.rb +34 -33
  69. data/lib/asciidoctor/pdf/roman_numeral.rb +80 -79
  70. data/lib/asciidoctor/pdf/sanitizer.rb +38 -37
  71. data/lib/asciidoctor/pdf/temporary_path.rb +10 -9
  72. data/lib/asciidoctor/pdf/text_transformer.rb +101 -100
  73. data/lib/asciidoctor/pdf/theme_loader.rb +258 -256
  74. data/lib/asciidoctor/pdf/version.rb +5 -4
  75. metadata +55 -6
  76. data/lib/asciidoctor/pdf/ext/rouge/themes/bw.rb +0 -39
  77. data/lib/asciidoctor/pdf/ext/ttfunk.rb +0 -9
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Rouge
3
4
  module Themes
4
5
  # A variation on the pastie style from Pygments, customized for Asciidoctor PDF
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'treetop'
3
4
  require 'set' unless defined? Set
4
5
  require_relative 'formatted_text/parser'
@@ -9,4 +10,5 @@ require_relative 'formatted_text/inline_destination_marker'
9
10
  require_relative 'formatted_text/inline_image_arranger'
10
11
  require_relative 'formatted_text/inline_image_renderer'
11
12
  require_relative 'formatted_text/inline_text_aligner'
13
+ require_relative 'formatted_text/source_wrap'
12
14
  require_relative 'formatted_text/text_background_and_border_renderer'
@@ -1,43 +1,44 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Asciidoctor
3
- module PDF
4
- module FormattedText
5
- class Formatter
6
- if defined? ::Asciidoctor::Logging
7
- include ::Asciidoctor::Logging
8
- else
9
- include ::Asciidoctor::LoggingShim
10
- end
4
+ module PDF
5
+ module FormattedText
6
+ class Formatter
7
+ if defined? ::Asciidoctor::Logging
8
+ include ::Asciidoctor::Logging
9
+ else
10
+ include ::Asciidoctor::LoggingShim
11
+ end
11
12
 
12
- FormattingSnifferPattern = /[<&]/
13
- WHITESPACE = " \t\n"
13
+ FormattingSnifferPattern = /[<&]/
14
+ WHITESPACE = %( \t\n)
14
15
 
15
- def initialize options = {}
16
- @parser = MarkupParser.new
17
- @transform = Transform.new merge_adjacent_text_nodes: true, theme: options[:theme]
18
- end
16
+ def initialize options = {}
17
+ @parser = MarkupParser.new
18
+ @transform = Transform.new merge_adjacent_text_nodes: true, theme: options[:theme]
19
+ end
19
20
 
20
- def format string, *args
21
- options = args[0] || {}
22
- string = string.tr_s(WHITESPACE, ' ') if options[:normalize]
23
- inherited = options[:inherited]
24
- if FormattingSnifferPattern.match? string
25
- if (parsed = @parser.parse(string))
26
- return @transform.apply(parsed.content, [], inherited)
27
- else
28
- logger.error %(failed to parse formatted text: #{string})
21
+ def format string, *args
22
+ options = args[0] || {}
23
+ string = string.tr_s WHITESPACE, ' ' if options[:normalize]
24
+ inherited = options[:inherited]
25
+ if FormattingSnifferPattern.match? string
26
+ if (parsed = @parser.parse string)
27
+ return @transform.apply parsed.content, [], inherited
28
+ else
29
+ logger.error %(failed to parse formatted text: #{string})
30
+ end
31
+ end
32
+ [inherited ? (inherited.merge text: string) : { text: string }]
33
+ end
34
+
35
+ # The original purpose of this method is to split paragraphs, but our formatter only works on paragraphs that have
36
+ # been presplit. Therefore, we just need to wrap the fragments in a single-element array (representing a single
37
+ # paragraph) and return them.
38
+ def array_paragraphs fragments
39
+ [fragments]
40
+ end
29
41
  end
30
42
  end
31
- [inherited ? (inherited.merge text: string) : { text: string }]
32
43
  end
33
-
34
- # The original purpose of this method is to split paragraphs, but our formatter only works on paragraphs that have
35
- # been presplit. Therefore, we just need to wrap the fragments in a single-element array (representing a single
36
- # paragraph) and return them.
37
- def array_paragraphs fragments
38
- [fragments]
39
- end
40
- end
41
- end
42
- end
43
44
  end
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Asciidoctor::PDF::FormattedText
3
- class FragmentPositionRenderer
4
- attr_reader :top, :right, :bottom, :left
4
+ class FragmentPositionRenderer
5
+ attr_reader :top, :right, :bottom, :left
5
6
 
6
- def render_behind fragment
7
- @top = fragment.top
8
- @right = (@left = fragment.left) + fragment.width
9
- @bottom = fragment.bottom
7
+ def render_behind fragment
8
+ @top = fragment.top
9
+ @right = (@left = fragment.left) + fragment.width
10
+ @bottom = fragment.bottom
11
+ end
10
12
  end
11
13
  end
12
- end
@@ -1,22 +1,21 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Asciidoctor::PDF::FormattedText
3
- module InlineDestinationMarker
4
- module_function
4
+ module InlineDestinationMarker
5
+ module_function
5
6
 
6
- # render_behind is called before the text is printed
7
- def render_behind fragment
8
- unless (pdf = fragment.document).scratch?
9
- if (name = fragment.format_state[:name])
10
- if fragment.format_state[:type] == :indexterm
11
- (pdf.instance_variable_get :@index).link_dest_to_page name, pdf.page_number
7
+ # render_behind is called before the text is printed
8
+ def render_behind fragment
9
+ unless (pdf = fragment.document).scratch?
10
+ if (name = fragment.format_state[:name])
11
+ (pdf.instance_variable_get :@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
12
17
  end
13
- # get precise position of the reference (x, y)
14
- dest_rect = fragment.absolute_bounding_box
15
- pdf.add_dest name, (pdf.dest_xyz dest_rect[0], dest_rect[-1])
16
- # prevent any text from being written
17
- fragment.conceal
18
18
  end
19
19
  end
20
20
  end
21
21
  end
22
- end
@@ -1,159 +1,138 @@
1
1
  # frozen_string_literal: true
2
- module Asciidoctor::PDF::FormattedText
3
- module InlineImageArranger
4
- include ::Asciidoctor::PDF::Measurements
5
- if defined? ::Asciidoctor::Logging
6
- include ::Asciidoctor::Logging
7
- else
8
- include ::Asciidoctor::LoggingShim
9
- end
10
2
 
11
- ImagePlaceholderChar = '.'
12
- begin
13
- require 'concurrent/map' unless defined? ::Concurrent::Map
14
- PlaceholderWidthCache = ::Concurrent::Map.new
15
- rescue
16
- PlaceholderWidthCache = {}
17
- end
18
- TemporaryPath = ::Asciidoctor::PDF::TemporaryPath
3
+ module Asciidoctor::PDF::FormattedText
4
+ module InlineImageArranger
5
+ include ::Asciidoctor::PDF::Measurements
6
+ if defined? ::Asciidoctor::Logging
7
+ include ::Asciidoctor::Logging
8
+ else
9
+ include ::Asciidoctor::LoggingShim
10
+ end
19
11
 
20
- def wrap fragments
21
- arrange_images fragments
22
- super
23
- end
12
+ # NOTE we must use a visible char or else Prawn won't allocate space for the fragment
13
+ ImagePlaceholderChar = '.'
14
+ TemporaryPath = ::Asciidoctor::PDF::TemporaryPath
24
15
 
25
- # Iterates over the fragments that represent inline images and prepares the
26
- # image data to be embedded into the document.
27
- #
28
- # This method populates the image_width, image_height, image_obj and
29
- # image_info (PNG only) keys on the fragment. The text is replaced with
30
- # placeholder text that will be used to reserve enough room in the line to
31
- # fit the image.
32
- #
33
- # The image height is scaled down to 75% of the specified width (px to pt
34
- # conversion). If the image height is more than 1.5x the height of the
35
- # surrounding line of text, the font size and line metrics of the fragment
36
- # are modified to fit the image in the line.
37
- #
38
- # If this is the scratch document, the image renderer callback is removed so
39
- # that the image is not embedded.
40
- #
41
- # When this method is called, the cursor is positioned at start of where this
42
- # group of fragments will be written (offset by the leading padding).
43
- #
44
- # This method is called each time the set of fragments overflow to another
45
- # page, so it's necessary to short-circuit if that case is detected.
46
- def arrange_images fragments
47
- doc = @document
48
- return if (raw_image_fragments = fragments.select {|f| (f.key? :image_path) && !(f.key? :image_obj) }).empty?
49
- scratch = doc.scratch?
50
- available_w = doc.bounds.width
51
- available_h = doc.page.empty? ? doc.cursor : doc.bounds.height
52
- raw_image_fragments.each do |fragment|
53
- drop = scratch
54
- begin
55
- image_path = fragment[:image_path]
16
+ def wrap fragments
17
+ arrange_images fragments
18
+ super
19
+ end
56
20
 
57
- # NOTE only attempt to convert an unresolved (i.e., String) value
58
- if ::String === (image_w = fragment[:image_width])
59
- image_w = [available_w, (image_w.end_with? '%') ? (image_w.to_f / 100 * available_w) : image_w.to_f].min
60
- end
21
+ # Iterates over the fragments that represent inline images and prepares the
22
+ # image data to be embedded into the document.
23
+ #
24
+ # This method populates the image_width, image_height, image_obj and
25
+ # image_info (PNG only) keys on the fragment. The text is replaced with
26
+ # placeholder text that will be used to reserve enough room in the line to
27
+ # fit the image.
28
+ #
29
+ # The image height is scaled down to 75% of the specified width (px to pt
30
+ # conversion). If the image height is more than 1.5x the height of the
31
+ # surrounding line of text, the font size and line metrics of the fragment
32
+ # are modified to fit the image in the line.
33
+ #
34
+ # If this is the scratch document, the image renderer callback is removed so
35
+ # that the image is not embedded.
36
+ #
37
+ # When this method is called, the cursor is positioned at start of where this
38
+ # group of fragments will be written (offset by the leading padding).
39
+ #
40
+ # This method is called each time the set of fragments overflow to another
41
+ # page, so it's necessary to short-circuit if that case is detected.
42
+ def arrange_images fragments
43
+ doc = @document
44
+ return if (raw_image_fragments = fragments.select {|f| (f.key? :image_path) && !(f.key? :image_obj) }).empty?
45
+ scratch = doc.scratch?
46
+ available_w = doc.bounds.width
47
+ available_h = doc.page.empty? ? doc.cursor : doc.bounds.height
48
+ raw_image_fragments.each do |fragment|
49
+ drop = scratch
50
+ begin
51
+ image_path = fragment[:image_path]
61
52
 
62
- # TODO make helper method to calculate width and height of image
63
- if fragment[:image_format] == 'svg'
64
- svg_obj = ::Prawn::SVG::Interface.new ::File.read(image_path, mode: 'r:UTF-8'), doc,
65
- at: doc.bounds.top_left,
66
- width: image_w,
67
- fallback_font_name: doc.fallback_svg_font_name,
68
- enable_web_requests: doc.allow_uri_read,
69
- enable_file_requests_with_root: (::File.dirname image_path),
70
- cache_images: doc.cache_uri
71
- svg_size = image_w ? svg_obj.document.sizing :
72
- # NOTE convert intrinsic dimensions to points; constrain to content width
73
- (svg_obj.resize width: [(to_pt svg_obj.document.sizing.output_width, :px), available_w].min)
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) > available_h
76
- image_w = (svg_size = svg_obj.resize height: (image_h = available_h)).output_width
77
- else
78
- image_w = svg_size.output_width
53
+ # NOTE only attempt to convert an unresolved (i.e., String) value
54
+ if ::String === (image_w = fragment[:image_width])
55
+ image_w = [available_w, (image_w.end_with? '%') ? (image_w.to_f / 100 * available_w) : image_w.to_f].min
79
56
  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_w
86
- if image_w == image_info.width
87
- image_h = image_info.height.to_f
57
+
58
+ max_image_h = fragment[:image_fit] == 'line' ? [available_h, doc.font.height].min : available_h
59
+
60
+ # TODO: make helper method to calculate width and height of image
61
+ if fragment[:image_format] == 'svg'
62
+ svg_obj = ::Prawn::SVG::Interface.new ::File.read(image_path, mode: 'r:UTF-8'), doc,
63
+ at: doc.bounds.top_left,
64
+ width: image_w,
65
+ fallback_font_name: doc.fallback_svg_font_name,
66
+ enable_web_requests: doc.allow_uri_read,
67
+ enable_file_requests_with_root: (::File.dirname image_path),
68
+ cache_images: doc.cache_uri
69
+ svg_size = image_w ? svg_obj.document.sizing :
70
+ # NOTE convert intrinsic dimensions to points; constrain to content width
71
+ (svg_obj.resize width: [(to_pt svg_obj.document.sizing.output_width, :px), available_w].min)
72
+ # NOTE the best we can do is make the image fit within full height of bounds
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
88
75
  else
89
- image_h = image_w * (image_info.height.fdiv image_info.width)
76
+ image_w = svg_size.output_width
90
77
  end
78
+ fragment[:image_obj] = svg_obj
91
79
  else
80
+ # TODO: cache image info based on path (Prawn caches based on SHA1 of content)
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
92
89
  # NOTE convert intrinsic dimensions to points; constrain to content width
93
- if (image_w = to_pt image_info.width, :px) > available_w
90
+ elsif (image_w = to_pt image_info.width, :px) > available_w
94
91
  image_h = (image_w = available_w) * (image_info.height.fdiv image_info.width)
95
92
  else
96
93
  image_h = to_pt image_info.height, :px
97
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
98
99
  end
99
- # NOTE the best we can do is make the image fit within full height of bounds
100
- image_w = (image_h = available_h) * (image_info.width.fdiv image_info.height) if image_h > available_h
101
- fragment[:image_obj] = image_obj
102
- fragment[:image_info] = image_info
103
- end
104
100
 
105
- spacer_w = nil
106
- doc.fragment_font fragment do
107
- # NOTE if image height exceeds line height by more than 1.5x, increase the line height
108
- # FIXME we could really use a nicer API from Prawn here; this is an ugly hack
109
- if (f_height = image_h) > (line_font = doc.font).height * 1.5
110
- # align with descender (equivalent to vertical-align: bottom in CSS)
111
- fragment[:ascender] = f_height - (fragment[:descender] = line_font.descender)
112
- doc.font_size(fragment[:size] = f_height * (doc.font_size / line_font.height))
113
- # align with baseline (roughly equivalent to vertical-align: baseline in CSS)
114
- #fragment[:ascender] = f_height
115
- #fragment[:descender] = 0
116
- #doc.font_size(fragment[:size] = (f_height + line_font.descender) * (doc.font_size / line_font.height))
117
- fragment[:line_height_increased] = true
118
- end
119
-
120
- unless (spacer_w = PlaceholderWidthCache[f_info = doc.font_info])
121
- spacer_w = PlaceholderWidthCache[f_info] = doc.width_of ImagePlaceholderChar
101
+ doc.fragment_font fragment do
102
+ # NOTE if image height exceeds line height by more than 1.5x, increase the line height
103
+ # FIXME: we could really use a nicer API from Prawn here; this is an ugly hack
104
+ if (f_height = image_h) > (line_font = doc.font).height * 1.5
105
+ # align with descender (equivalent to vertical-align: bottom in CSS)
106
+ fragment[:ascender] = f_height - (fragment[:descender] = line_font.descender)
107
+ doc.font_size (fragment[:size] = f_height * (doc.font_size / line_font.height))
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
122
114
  end
123
- end
124
115
 
125
- # NOTE make room for image by repeating image placeholder character, using character spacing to fine-tune
126
- # NOTE image_width is constrained to available_w, so we don't have to check for overflow
127
- spacer_cnt, remainder = image_w.divmod spacer_w
128
- if spacer_cnt > 0
129
- fragment[:text] = ImagePlaceholderChar * spacer_cnt
130
- fragment[:character_spacing] = remainder.fdiv spacer_cnt if remainder > 0
131
- else
132
116
  fragment[:text] = ImagePlaceholderChar
133
- fragment[:character_spacing] = -(spacer_w - remainder)
134
- end
135
-
136
- # FIXME we could use a nicer API from Prawn here that lets us reserve a fragment width without text
137
- #fragment[:image_width] = fragment[:width] = image_w
138
- fragment[:image_width] = image_w
139
- fragment[:image_height] = image_h
140
- rescue
141
- logger.warn %(could not embed image: #{image_path}; #{$!.message}#{::Prawn::Errors::UnsupportedImageType === $! ? '; install prawn-gmagick gem to add support' : ''})
142
- drop = true # delegate to cleanup logic in ensure block
143
- ensure
144
- # NOTE skip rendering image in scratch document or if image can't be loaded
145
- if drop
146
- fragment.delete :callback
147
- fragment.delete :image_info
148
- # NOTE retain key to indicate we've visited fragment already
149
- fragment[:image_obj] = nil
150
- # NOTE in main document, temporary image path is unlinked by renderer
151
- image_path.unlink if TemporaryPath === image_path && image_path.exist?
117
+ fragment[:image_width] = fragment[:width] = image_w
118
+ fragment[:image_height] = image_h
119
+ rescue
120
+ logger.warn %(could not embed image: #{image_path}; #{$!.message}#{::Prawn::Errors::UnsupportedImageType === $! ? '; install prawn-gmagick gem to add support' : ''})
121
+ drop = true # delegate to cleanup logic in ensure block
122
+ ensure
123
+ # NOTE skip rendering image in scratch document or if image can't be loaded
124
+ if drop
125
+ fragment.delete :callback
126
+ fragment.delete :image_info
127
+ # NOTE retain key to indicate we've visited fragment already
128
+ fragment[:image_obj] = nil
129
+ # NOTE in main document, temporary image path is unlinked by renderer
130
+ image_path.unlink if TemporaryPath === image_path && image_path.exist?
131
+ end
152
132
  end
153
133
  end
154
134
  end
155
135
  end
156
- end
157
136
 
158
- ::Prawn::Text::Formatted::Box.prepend InlineImageArranger
137
+ ::Prawn::Text::Formatted::Box.prepend InlineImageArranger
159
138
  end
@@ -1,47 +1,49 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Asciidoctor::PDF::FormattedText
3
- module InlineImageRenderer
4
- TemporaryPath = ::Asciidoctor::PDF::TemporaryPath
5
- module_function
4
+ module InlineImageRenderer
5
+ TemporaryPath = ::Asciidoctor::PDF::TemporaryPath
6
6
 
7
- # Embeds the image object in this fragment into the document in place of the
8
- # text that was previously used to reserve space for the image in the line.
9
- #
10
- # If the image height is less than 1.5x the height of the surrounding text,
11
- # it is centered vertically in the line. If the image height is greater, then
12
- # the image is aligned to the bottom of the text.
13
- #
14
- # Note that render_behind is called before the text is printed.
15
- #
16
- # This handler is only used on the main document (not the scratch document).
17
- #
18
- def render_behind fragment
19
- pdf = fragment.document
20
- data = fragment.format_state
21
- image_top = if data.key? :line_height_increased
22
- # align image to bottom of line (differs from fragment.top by descender value)
23
- fragment.bottom + data[:image_height]
24
- else
25
- # center image in line
26
- fragment.top - ((fragment.height - data[:image_height]) / 2.0)
27
- end
28
- image_left = fragment.left + ((fragment.width - data[:image_width]) / 2.0)
29
- case data[:image_format]
30
- when 'svg'
31
- (image_obj = data[:image_obj]).options[:at] = [image_left, image_top]
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)
34
- pdf.float { image_obj.draw }
35
- else
36
- pdf.embed_image data[:image_obj], data[:image_info], at: [image_left, image_top], width: data[:image_width], height: data[:image_height]
37
- end
38
- # ...or use the public interface, loading the image again
39
- #pdf.image data[:image_path], at: [image_left, image_top], width: data[:image_width]
7
+ module_function
40
8
 
41
- # prevent any text from being written
42
- fragment.conceal
43
- ensure
44
- data[:image_path].unlink if TemporaryPath === data[:image_path] && data[:image_path].exist?
9
+ # Embeds the image object in this fragment into the document in place of the
10
+ # text that was previously used to reserve space for the image in the line.
11
+ #
12
+ # If the image height is less than 1.5x the height of the surrounding text,
13
+ # it is centered vertically in the line. If the image height is greater, then
14
+ # the image is aligned to the bottom of the text.
15
+ #
16
+ # Note that render_behind is called before the text is printed.
17
+ #
18
+ # This handler is only used on the main document (not the scratch document).
19
+ #
20
+ def render_behind fragment
21
+ pdf = fragment.document
22
+ data = fragment.format_state
23
+ if data.key? :line_height_increased
24
+ # align image to bottom of line (differs from fragment.top by descender value)
25
+ image_top = fragment.bottom + data[:image_height]
26
+ else
27
+ # center image in line
28
+ image_top = fragment.top - ((fragment.height - data[:image_height]) / 2.0)
29
+ end
30
+ image_left = fragment.left + ((fragment.width - data[:image_width]) / 2.0)
31
+ case data[:image_format]
32
+ when 'svg'
33
+ (image_obj = data[:image_obj]).options[:at] = [image_left, image_top]
34
+ # NOTE prawn-svg messes with the cursor; use float to workaround
35
+ # 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)
36
+ pdf.float { image_obj.draw }
37
+ else
38
+ pdf.embed_image data[:image_obj], data[:image_info], at: [image_left, image_top], width: data[:image_width], height: data[:image_height]
39
+ end
40
+ # ...or use the public interface, loading the image again
41
+ #pdf.image data[:image_path], at: [image_left, image_top], width: data[:image_width]
42
+
43
+ # prevent any text from being written
44
+ fragment.conceal
45
+ ensure
46
+ data[:image_path].unlink if TemporaryPath === data[:image_path] && data[:image_path].exist?
47
+ end
45
48
  end
46
49
  end
47
- end