asciidoctor-pdf 2.0.4 → 2.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ff0a79d0d99869a25e820f003920cb1cbb8485f103c73c6f51e6cb74b97ddcb5
4
- data.tar.gz: 318f9318f55317e4483f8e566a58db5aa4407642e75a2ece66dfa1f2f150c8bf
3
+ metadata.gz: f836f6c86c31a3bbd792bba4608f397422361bcc5b297355eccab266a3a5ac0b
4
+ data.tar.gz: b31b434d0d7bede025b4f3c25e71a518f120a66840dfb7df72308d17fda9bd8e
5
5
  SHA512:
6
- metadata.gz: d1ea1f2ad102f118e1de4d90ce4cf763db78f691ac6ddf5c93d9f2183b3fc0736a6767d20272d8b86815f0902088b2c42ed3dc72e59d587934d6738428271712
7
- data.tar.gz: e686737ae4e56e8bd1f82bb916fb49bf77d937d226fec53f24753144d43304efe99e55c42dcaca27372e08ab1695dd3c711e727687ebbf17bc38a99a99b9ef5d
6
+ metadata.gz: 84899cfb74ce8ef2c97111d585e73529318c3f0a44756f75674338f58c1d46693925fe1f9d42b9666f07d8a1bed68f606ec3ec2b664816d0c92998494e90a39a
7
+ data.tar.gz: a50053c502cf572929c49802208e18faa9f1e5bf0a2f3e47972c3863fafa3c43e157425e7b3c5a1ad12cc0e301d8e461a108907e48f5b80aaa0f05938dc2e6a2
data/CHANGELOG.adoc CHANGED
@@ -5,6 +5,47 @@
5
5
  This document provides a high-level view of the changes to the {project-name} by release.
6
6
  For a detailed view of what has changed, refer to the {url-repo}/commits/main[commit history] on GitHub.
7
7
 
8
+ == 2.0.7 (2022-06-03) - @mojavelinux
9
+
10
+ Improvements::
11
+
12
+ * don't recommend prawn-gmagick if PNG or JPG is corrupt or incomplete
13
+ * add helper method to determine when to recommend the prawn-gmagick gem
14
+
15
+ Bug Fixes::
16
+
17
+ * fix crash when doctitle or section title with automatic ID contains inline image without explicit width (#2228)
18
+ * use prawn-gmagick, if available, to read raster image referenced by SVG (#2223)
19
+ * allow image path in SVG to refer to any location within Asciidoctor jail (no restriction if safe mode is unsafe) (#1941)
20
+
21
+ === Details
22
+
23
+ {url-repo}/releases/tag/v2.0.7[git tag] | {url-repo}/compare/v2.0.6\...v2.0.7[full diff]
24
+
25
+ == 2.0.6 (2022-05-30) - @mojavelinux
26
+
27
+ Bug Fixes::
28
+
29
+ * indent content of collapsible block and apply bottom margin to match style of HTML output (#2219)
30
+ * patch prawn-gmagick to reread bit depth of a PNG image if it extracts the wrong value (#2216)
31
+ * interpret width of SVG correctly when width is defined in file using px units (#2215)
32
+ * don't crash if inline role defines border width but not border color
33
+
34
+ === Details
35
+
36
+ {url-repo}/releases/tag/v2.0.6[git tag] | {url-repo}/compare/v2.0.5\...v2.0.6[full diff]
37
+
38
+ == 2.0.5 (2022-05-26) - @mojavelinux
39
+
40
+ Bug Fixes::
41
+
42
+ * do not filter TOC entries without an ID when computing the TOC extent (#2210)
43
+ * fix width of multi-word phrase with background and border offset (#2059)
44
+
45
+ === Details
46
+
47
+ {url-repo}/releases/tag/v2.0.5[git tag] | {url-repo}/compare/v2.0.4\...v2.0.5[full diff]
48
+
8
49
  == 2.0.4 (2022-05-25) - @mojavelinux
9
50
 
10
51
  Bug Fixes::
data/README.adoc CHANGED
@@ -1,6 +1,6 @@
1
1
  = Asciidoctor PDF: A native PDF converter for AsciiDoc
2
2
  Dan Allen <https://github.com/mojavelinux[@mojavelinux]>; Sarah White <https://github.com/graphitefriction[@graphitefriction]>
3
- v2.0.4, 2022-05-25
3
+ v2.0.7, 2022-06-03
4
4
  // Settings:
5
5
  :experimental:
6
6
  :idprefix:
@@ -24,7 +24,7 @@ endif::[]
24
24
  :project-handle: asciidoctor-pdf
25
25
  // Variables:
26
26
  :release-line: 2.0.x
27
- :release-version: 2.0.4
27
+ :release-version: 2.0.7
28
28
  // URLs:
29
29
  :url-gem: https://rubygems.org/gems/asciidoctor-pdf
30
30
  :url-project: https://github.com/asciidoctor/asciidoctor-pdf
@@ -6,9 +6,6 @@ require_relative 'pdfmark'
6
6
  require_relative 'roman_numeral'
7
7
  require_relative 'section_info_by_page'
8
8
 
9
- autoload :StringIO, 'stringio'
10
- autoload :Tempfile, 'tempfile'
11
-
12
9
  module Asciidoctor
13
10
  module PDF
14
11
  class Converter < ::Prawn::Document
@@ -23,6 +20,8 @@ module Asciidoctor
23
20
 
24
21
  attr_reader :cache_uri
25
22
 
23
+ attr_reader :jail_dir
24
+
26
25
  attr_accessor :font_color
27
26
 
28
27
  attr_accessor :font_scale
@@ -153,7 +152,7 @@ module Asciidoctor
153
152
  log :warn, %(missing convert handler for #{name} node in #{@backend} backend)
154
153
  end
155
154
  # NOTE: inline node handlers generate HTML-like strings; all other handlers write directly to the PDF object
156
- ::Asciidoctor::Inline === node ? result : self
155
+ node.inline? ? result : self
157
156
  end
158
157
 
159
158
  def convert_document doc
@@ -339,7 +338,11 @@ module Asciidoctor
339
338
  #@page_opts = { size: pdf_opts[:page_size], layout: pdf_opts[:page_layout] }
340
339
  ((::Prawn::Document.instance_method :initialize).bind self).call pdf_opts
341
340
  renderer.min_version (@pdf_version = PDFVersions[doc.attr 'pdf-version'])
342
- @media = doc.attr 'media', 'screen'
341
+ @tmp_files ||= {}
342
+ @allow_uri_read = doc.attr? 'allow-uri-read'
343
+ @cache_uri = doc.attr? 'cache-uri'
344
+ @jail_dir = doc.safe < ::Asciidoctor::SafeMode::SAFE ? nil : doc.base_dir
345
+ @media ||= doc.attr 'media', 'screen'
343
346
  @page_margin_by_side = { recto: (page_margin_recto = page_margin), verso: (page_margin_verso = page_margin), cover: page_margin }
344
347
  case doc.attr 'pdf-folio-placement', (@media == 'prepress' ? 'physical' : 'virtual')
345
348
  when 'physical'
@@ -364,13 +367,6 @@ module Asciidoctor
364
367
  else
365
368
  @ppbook = nil
366
369
  end
367
- # QUESTION: should ThemeLoader handle registering fonts instead?
368
- register_fonts theme.font_catalog, ((doc.attr 'pdf-fontsdir')&.sub '{docdir}', (doc.attr 'docdir')) || 'GEM_FONTS_DIR'
369
- default_kerning theme.base_font_kerning != 'none'
370
- @fallback_fonts = Array theme.font_fallbacks
371
- @allow_uri_read = doc.attr? 'allow-uri-read'
372
- @cache_uri = doc.attr? 'cache-uri'
373
- @tmp_files = {}
374
370
  if (bg_image = resolve_background_image doc, theme, 'page-background-image')&.first
375
371
  @page_bg_image = { verso: bg_image, recto: bg_image }
376
372
  else
@@ -383,6 +379,10 @@ module Asciidoctor
383
379
  @page_bg_image[:recto] = bg_image[0] && bg_image
384
380
  end
385
381
  @page_bg_color = resolve_theme_color :page_background_color, 'FFFFFF'
382
+ # QUESTION: should ThemeLoader handle registering fonts instead?
383
+ register_fonts theme.font_catalog, ((doc.attr 'pdf-fontsdir')&.sub '{docdir}', (doc.attr 'docdir')) || 'GEM_FONTS_DIR'
384
+ default_kerning theme.base_font_kerning != 'none'
385
+ @fallback_fonts = Array theme.font_fallbacks
386
386
  @root_font_size = theme.base_font_size
387
387
  @font_scale = 1
388
388
  @font_color = theme.base_font_color
@@ -939,7 +939,7 @@ module Asciidoctor
939
939
  height: label_height,
940
940
  fallback_font_name: fallback_svg_font_name,
941
941
  enable_web_requests: allow_uri_read ? (method :load_open_uri).to_proc : false,
942
- enable_file_requests_with_root: (::File.dirname icon_path),
942
+ enable_file_requests_with_root: { base: (::File.dirname icon_path), root: @jail_dir },
943
943
  cache_images: cache_uri
944
944
  svg_obj.resize height: label_height if svg_obj.document.sizing.output_height > label_height
945
945
  svg_obj.draw
@@ -1167,8 +1167,26 @@ module Asciidoctor
1167
1167
  alias convert_literal convert_code
1168
1168
  alias convert_listing_or_literal convert_code
1169
1169
 
1170
+ def convert_collapsible node
1171
+ id = node.id
1172
+ title = (collapsible_marker = %(\u25bc )) + (node.title? ? node.title : 'Details')
1173
+ indent_by = theme_font(:caption) { rendered_width_of_string collapsible_marker }
1174
+ if !at_page_top? && (id || (node.option? 'unbreakable'))
1175
+ arrange_block node do
1176
+ add_dest_for_block node if id
1177
+ tare_first_page_content_stream { ink_caption title }
1178
+ indent(indent_by) { traverse node }
1179
+ end
1180
+ else
1181
+ add_dest_for_block node if id
1182
+ tare_first_page_content_stream { ink_caption title }
1183
+ indent(indent_by) { traverse node }
1184
+ end
1185
+ theme_margin :block, :bottom, (next_enclosed_block node)
1186
+ end
1187
+
1170
1188
  def convert_example node
1171
- return convert_open node if node.option? 'collapsible'
1189
+ return convert_collapsible node if node.option? 'collapsible'
1172
1190
  caption_bottom = @theme.example_caption_end&.to_sym == :bottom
1173
1191
  arrange_block node do |extent|
1174
1192
  add_dest_for_block node if node.id
@@ -1193,14 +1211,12 @@ module Asciidoctor
1193
1211
  if !at_page_top? && (has_title || id || (node.option? 'unbreakable'))
1194
1212
  arrange_block node do
1195
1213
  add_dest_for_block node if id
1196
- tare_first_page_content_stream do
1197
- node.context == :example ? (ink_caption %(\u25bc #{node.title})) : (ink_caption node, labeled: false)
1198
- end if has_title
1214
+ tare_first_page_content_stream { ink_caption node, labeled: false } if has_title
1199
1215
  traverse node
1200
1216
  end
1201
1217
  else
1202
1218
  add_dest_for_block node if id
1203
- node.context == :example ? (ink_caption %(\u25bc #{node.title})) : (ink_caption node, labeled: false) if has_title
1219
+ ink_caption node, labeled: false if has_title
1204
1220
  traverse node
1205
1221
  end
1206
1222
  end
@@ -1718,7 +1734,7 @@ module Asciidoctor
1718
1734
  file_request_root = false
1719
1735
  else
1720
1736
  svg_data = ::File.read image_path, mode: 'r:UTF-8'
1721
- file_request_root = ::File.dirname image_path
1737
+ file_request_root = { base: (::File.dirname image_path), root: @jail_dir }
1722
1738
  end
1723
1739
  svg_obj = ::Prawn::SVG::Interface.new svg_data, self,
1724
1740
  position: alignment,
@@ -1798,7 +1814,7 @@ module Asciidoctor
1798
1814
  end
1799
1815
  rescue => e
1800
1816
  raise if ::StopIteration === e
1801
- on_image_error :exception, node, target, (opts.merge align: alignment, message: %(could not embed image: #{image_path}; #{e.message}#{::Prawn::Errors::UnsupportedImageType === e && !(defined? ::GMagick::Image) ? '; install prawn-gmagick gem to add support' : ''}))
1817
+ on_image_error :exception, node, target, (opts.merge align: alignment, message: %(could not embed image: #{image_path}; #{e.message}#{(recommend_prawn_gmagick? e, image_format) ? %(; install prawn-gmagick gem to add support for #{image_format&.upcase || 'unknown'} image format) : ''}))
1802
1818
  end
1803
1819
  end
1804
1820
 
@@ -2492,14 +2508,19 @@ module Asciidoctor
2492
2508
  # NOTE: an image with a data URI is handled using a temporary file
2493
2509
  elsif (image_path = resolve_image_path node, target, image_format)
2494
2510
  if ::File.readable? image_path
2511
+ class_attr = (role = node.role) ? %( class="#{role}") : ''
2512
+ fit_attr = (fit = node.attr 'fit') ? %( fit="#{fit}") : ''
2495
2513
  if (width = resolve_explicit_width node.attributes)
2496
- width += (intrinsic_image_dimensions image_path, image_format)[:width].to_s if node.parent.context == :table_cell && ::String === width && (width.end_with? '%')
2514
+ if node.parent.context == :table_cell && ::String === width && (width.end_with? '%')
2515
+ width += (intrinsic_image_dimensions image_path, image_format)[:width].to_s
2516
+ end
2517
+ width_attr = %( width="#{width}")
2518
+ elsif state # check that converter is initialized
2519
+ width_attr = %( width="#{(intrinsic_image_dimensions image_path, image_format)[:width]}")
2497
2520
  else
2498
- width = (intrinsic_image_dimensions image_path, image_format)[:width]
2521
+ width_attr = ' width="auto"' # defer operation until arranger runs
2499
2522
  end
2500
- class_attr = (role = node.role) ? %( class="#{role}") : ''
2501
- fit_attr = (fit = node.attr 'fit') ? %( fit="#{fit}") : ''
2502
- img = %(<img src="#{image_path}" format="#{image_format}" alt="#{encode_quotes node.attr 'alt'}" width="#{width}"#{class_attr}#{fit_attr}>)
2523
+ img = %(<img src="#{image_path}" format="#{image_format}" alt="#{encode_quotes node.attr 'alt'}"#{width_attr}#{class_attr}#{fit_attr}>)
2503
2524
  else
2504
2525
  log :warn, %(image to embed not found or not readable: #{image_path})
2505
2526
  img = %([#{node.attr 'alt'}&#93;)
@@ -3001,7 +3022,7 @@ module Asciidoctor
3001
3022
  end
3002
3023
  end
3003
3024
  end
3004
- theme_font_cascade [:caption, category_caption] do
3025
+ theme_font_cascade ['caption', category_caption] do
3005
3026
  if ((opts.delete :end) || (opts.delete :side) || :top) == :top
3006
3027
  margin = { top: caption_margin_outside, bottom: caption_margin_inside }
3007
3028
  else
@@ -3758,7 +3779,6 @@ module Asciidoctor
3758
3779
  next if (num_levels_for_entry = (entry.attr 'toclevels', num_levels).to_i) < (entry_level = entry.level + 1).pred ||
3759
3780
  ((entry.option? 'notitle') && entry == entry.document.last_child && entry.empty?)
3760
3781
  theme_font :toc, level: entry_level do
3761
- next unless (entry_anchor = (entry.attr 'pdf-anchor') || entry.id)
3762
3782
  entry_title = entry.context == :section ? entry.numbered_title : (entry.title? ? entry.title : (entry.xreftext 'basic'))
3763
3783
  next if entry_title.empty?
3764
3784
  entry_title = transform_text entry_title, @text_transform if @text_transform
@@ -3770,6 +3790,7 @@ module Asciidoctor
3770
3790
  ink_prose entry_title, anchor: true, normalize: false, hanging_indent: hanging_indent, normalize_line_height: true, margin: 0
3771
3791
  end
3772
3792
  else
3793
+ entry_anchor = (entry.attr 'pdf-anchor') || entry.id
3773
3794
  if !(physical_pgnum = entry.attr 'pdf-page-start') &&
3774
3795
  (target_page_ref = (get_dest entry_anchor)&.first) &&
3775
3796
  (target_page_idx = state.pages.index {|candidate| candidate.dictionary == target_page_ref })
@@ -3825,6 +3846,27 @@ module Asciidoctor
3825
3846
  end
3826
3847
  end
3827
3848
 
3849
+ # Retrieve the intrinsic image dimensions for the specified path in pt.
3850
+ #
3851
+ # Returns a Hash containing :width and :height keys that map to the image's
3852
+ # intrinsic width and height values (in pt).
3853
+ def intrinsic_image_dimensions path, format
3854
+ if format == 'svg'
3855
+ # NOTE: prawn-svg automatically converts intrinsic width and height to pt
3856
+ img_obj = ::Prawn::SVG::Interface.new (::File.read path, mode: 'r:UTF-8'), self, {}
3857
+ img_size = img_obj.document.sizing
3858
+ { width: img_size.output_width, height: img_size.output_height }
3859
+ else
3860
+ # NOTE: build_image_object caches image data previously loaded
3861
+ # NOTE: build_image_object computes intrinsic width and height in px
3862
+ _, img_size = ::File.open(path, 'rb') {|fd| build_image_object fd }
3863
+ { width: (to_pt img_size.width, :px), height: (to_pt img_size.height, :px) }
3864
+ end
3865
+ rescue
3866
+ # NOTE: image can't be read, so it won't be used anyway
3867
+ { width: 0, height: 0 }
3868
+ end
3869
+
3828
3870
  # Sends the specified message to the log unless this method is called from the scratch document
3829
3871
  def log severity, message = nil, &block
3830
3872
  logger.send severity, message, &block unless scratch?
@@ -4033,7 +4075,7 @@ module Asciidoctor
4033
4075
  def resolve_image_options image_path, image_format, image_attrs, opts = {}
4034
4076
  if image_format == 'svg'
4035
4077
  image_opts = {
4036
- enable_file_requests_with_root: (::File.dirname image_path),
4078
+ enable_file_requests_with_root: { base: (::File.dirname image_path), root: @jail_dir },
4037
4079
  enable_web_requests: allow_uri_read ? (method :load_open_uri).to_proc : false,
4038
4080
  cache_images: cache_uri,
4039
4081
  fallback_font_name: fallback_svg_font_name,
@@ -4120,6 +4162,7 @@ module Asciidoctor
4120
4162
  else
4121
4163
  imagesdir = relative_to
4122
4164
  end
4165
+ @tmp_files ||= {}
4123
4166
  # NOTE: base64 logic currently used for inline images
4124
4167
  if ::Base64 === image_path
4125
4168
  return @tmp_files[image_path] if @tmp_files.key? image_path
@@ -4346,7 +4389,7 @@ module Asciidoctor
4346
4389
  end
4347
4390
 
4348
4391
  def theme_font_cascade categories, &block
4349
- if ::Array === (category = (categories = categories.dup).shift)
4392
+ if ::Array === (category = (categories = categories.uniq).shift)
4350
4393
  category, opts = category
4351
4394
  else
4352
4395
  opts = {}
@@ -257,10 +257,10 @@ module Asciidoctor
257
257
  # Prevents at_page_top? from returning true while yielding to the specified block.
258
258
  #
259
259
  def conceal_page_top
260
- margin_box.instance_variable_set :@y, (old_top = margin_box.absolute_top) + 0.0001
260
+ @margin_box.instance_variable_set :@y, (old_top = @margin_box.absolute_top) + 0.0001
261
261
  yield
262
262
  ensure
263
- margin_box.instance_variable_set :@y, old_top
263
+ @margin_box.instance_variable_set :@y, old_top
264
264
  end
265
265
 
266
266
  # Returns whether the current page is the last page in the document.
@@ -5,8 +5,12 @@ Prawn::Text::Formatted::Fragment.prepend (Module.new do
5
5
 
6
6
  # Prevent fragment from being written by discarding the text, optionally forcing the width to 0
7
7
  def conceal force_width_to_zero = false
8
- @text = ''
9
- @width = 0 if force_width_to_zero
8
+ if force_width_to_zero
9
+ @width = 0
10
+ @text = ''
11
+ else
12
+ @text = ' ' * space_count # preserve space_count so width is still computed correctly
13
+ end
10
14
  end
11
15
 
12
16
  # Don't strip soft hyphens when repacking unretrieved fragments
@@ -33,25 +33,8 @@ module Asciidoctor
33
33
  end
34
34
  end
35
35
 
36
- # Retrieve the intrinsic image dimensions for the specified path in pt.
37
- #
38
- # Returns a Hash containing :width and :height keys that map to the image's
39
- # intrinsic width and height values (in pt).
40
- def intrinsic_image_dimensions path, format
41
- if format == 'svg'
42
- # NOTE: prawn-svg computes intrinsic width and height in pt
43
- img_obj = ::Prawn::SVG::Interface.new (::File.read path, mode: 'r:UTF-8'), self, {}
44
- img_size = img_obj.document.sizing
45
- { width: img_size.output_width, height: img_size.output_height }
46
- else
47
- # NOTE: build_image_object caches image data previously loaded
48
- # NOTE: build_image_object computes intrinsic width and height in px
49
- _, img_size = ::File.open(path, 'rb') {|fd| build_image_object fd }
50
- { width: (to_pt img_size.width, :px), height: (to_pt img_size.height, :px) }
51
- end
52
- rescue
53
- # NOTE: image cannot be read, so it won't be used anyway
54
- { width: 0, height: 0 }
36
+ def recommend_prawn_gmagick? err, image_format
37
+ ::Prawn::Errors::UnsupportedImageType === err && !(defined? ::GMagick::Image) && ((err.message.include? 'PNG') || (%w(jpg png).none? image_format))
55
38
  end
56
39
  end
57
40
 
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'prawn/gmagick'
5
+ rescue LoadError # rubocop:disable Lint/SuppressedException
6
+ end unless defined? GMagick::Image
7
+
8
+ Gmagick.prepend (Module.new do
9
+ def initialize image_blob
10
+ super
11
+ # apply patch for https://github.com/packetmonkey/prawn-gmagick/issues/19
12
+ if bits != 8 && (GMagick::Image.format image_blob) == 'PNG'
13
+ (io = StringIO.new image_blob).read 8
14
+ chunk_size = io.read 4
15
+ self.bits = ((io.read chunk_size.unpack1 'N').unpack 'NNC')[-1] if (io.read 4) == 'IHDR'
16
+ end
17
+ end
18
+ end) if defined? GMagick::Image
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ Prawn::SVG::Calculators::DocumentSizing.prepend (Module.new do
4
+ def initialize *_args
5
+ super
6
+ @document_width = @document_width.to_f * 0.75 if @document_width&.end_with? 'px'
7
+ @document_height = @document_height.to_f * 0.75 if @document_height&.end_with? 'px'
8
+ end
9
+ end)
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ Prawn::SVG::Elements::Image.prepend (Module.new do
4
+ def image_dimensions data
5
+ unless (handler = find_image_handler data)
6
+ raise ::Prawn::SVG::Elements::Base::SkipElementError, 'Unsupported image type supplied to image tag'
7
+ end
8
+ image = handler.new data
9
+ [image.width.to_f, image.height.to_f]
10
+ end
11
+
12
+ def find_image_handler data
13
+ Prawn.image_handler.find data rescue nil
14
+ end
15
+ end)
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ Prawn::SVG::Loaders::File.prepend (Module.new do
4
+ attr_reader :jail_path
5
+
6
+ def initialize root_path
7
+ if Hash === root_path
8
+ @jail_path = root_path[:root]
9
+ root_path = root_path[:base]
10
+ super
11
+ else
12
+ super
13
+ @jail_path = self.root_path
14
+ end
15
+ end
16
+
17
+ def assert_valid_path! path
18
+ if jail_path && !(path.start_with? %(#{jail_path}#{File::SEPARATOR}))
19
+ raise Prawn::SVG::UrlLoader::Error, %(file path points to location outside of jail #{jail_path})
20
+ end
21
+ end
22
+ end)
@@ -1,7 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'prawn-svg'
4
+ require_relative 'prawn-svg/calculators/document_sizing'
5
+ require_relative 'prawn-svg/elements/image'
4
6
  require_relative 'prawn-svg/loaders/data'
7
+ require_relative 'prawn-svg/loaders/file'
5
8
  require_relative 'prawn-svg/loaders/web'
6
9
  require_relative 'prawn-svg/url_loader'
7
10
  # NOTE: disable system fonts since they're non-portable
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # NOTE: patch float precision constant so prawn-table does not fail to arrange cells that span columns (see #1835)
4
+ Prawn.send :remove_const, :FLOAT_PRECISION
5
+ Prawn::FLOAT_PRECISION = 1e-3
6
+
3
7
  # the following are organized under the Asciidoctor::Prawn namespace
4
8
  require_relative 'prawn/document/column_box'
5
9
  require_relative 'prawn/font_metric_cache'
@@ -4,5 +4,6 @@ require_relative 'ext/core'
4
4
  require_relative 'ext/asciidoctor'
5
5
  require_relative 'ext/pdf-core'
6
6
  require_relative 'ext/prawn'
7
+ require_relative 'ext/prawn-gmagick'
7
8
  require_relative 'ext/prawn-svg'
8
9
  require_relative 'ext/prawn-table'
@@ -48,10 +48,11 @@ module Asciidoctor::PDF::FormattedText
48
48
  drop = scratch
49
49
  end
50
50
  image_path = fragment[:image_path]
51
- image_w = fragment[:image_width] || '100%'
52
-
53
- # NOTE: intrinsic width is stored behind % symbol
54
- if (pctidx = image_w.index '%') && pctidx + 1 < image_w.length
51
+ image_format = fragment[:image_format]
52
+ if (image_w = fragment[:image_width] || '100%') == 'auto'
53
+ image_w = nil # use intrinsic width
54
+ elsif (pctidx = image_w.index '%') && pctidx + 1 < image_w.length
55
+ # NOTE: intrinsic width is stored behind % symbol
55
56
  pct = (image_w.slice 0, pctidx).to_f / 100
56
57
  intrinsic_w = (image_w.slice pctidx + 1, image_w.length).to_f
57
58
  image_w = [available_w, pct * intrinsic_w].min
@@ -62,26 +63,33 @@ module Asciidoctor::PDF::FormattedText
62
63
  max_image_h = fragment[:image_fit] == 'line' ? [available_h, doc.font.height].min : available_h
63
64
 
64
65
  # TODO: make helper method to calculate width and height of image
65
- if fragment[:image_format] == 'svg'
66
+ if image_format == 'svg'
66
67
  svg_obj = ::Prawn::SVG::Interface.new ::File.read(image_path, mode: 'r:UTF-8'), doc,
67
68
  at: doc.bounds.top_left,
68
69
  width: image_w,
69
70
  fallback_font_name: doc.fallback_svg_font_name,
70
71
  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
+ enable_file_requests_with_root: { base: (::File.dirname image_path), root: doc.jail_dir },
72
73
  cache_images: doc.cache_uri
73
74
  svg_size = svg_obj.document.sizing
74
75
  # NOTE: the best we can do is make the image fit within full height of bounds
75
76
  if (image_h = svg_size.output_height) > max_image_h
76
77
  image_w = (svg_obj.resize height: (image_h = max_image_h)).output_width
77
- else
78
+ elsif image_w
78
79
  image_w = svg_size.output_width
80
+ else
81
+ fragment[:image_width] = (image_w = svg_size.output_width).to_s
82
+ image_w = available_w if image_w > available_w
79
83
  end
80
84
  fragment[:image_obj] = svg_obj
81
85
  else
82
86
  # TODO: cache image info based on path (Prawn caches based on SHA1 of content)
83
87
  # NOTE: image_obj is constrained to image_width by renderer
84
88
  image_obj, image_info = ::File.open(image_path, 'rb') {|fd| doc.build_image_object fd }
89
+ unless image_w
90
+ fragment[:image_width] = (image_w = to_pt image_info.width, :px).to_s
91
+ image_w = available_w if image_w > available_w
92
+ end
85
93
  if (image_h = image_w * (image_info.height.fdiv image_info.width)) > max_image_h
86
94
  # NOTE: the best we can do is make the image fit within full height of bounds
87
95
  image_w = (image_h = max_image_h) * (image_info.width.fdiv image_info.height)
@@ -117,7 +125,7 @@ module Asciidoctor::PDF::FormattedText
117
125
  fragment[:image_width] = fragment[:width] = image_w
118
126
  fragment[:image_height] = image_h
119
127
  rescue
120
- logger.warn %(could not embed image: #{image_path}; #{$!.message}#{::Prawn::Errors::UnsupportedImageType === $! && !(defined? ::GMagick::Image) ? '; install prawn-gmagick gem to add support' : ''}) unless scratch
128
+ logger.warn %(could not embed image: #{image_path}; #{$!.message}#{(doc.recommend_prawn_gmagick? $!, image_format) ? %(; install prawn-gmagick gem to add support for #{image_format&.upcase || 'unknown'} image format) : ''}) unless scratch
121
129
  drop = true # delegate to cleanup logic in ensure block
122
130
  ensure
123
131
  # NOTE: skip rendering image in scratch document or if image can't be loaded
@@ -9,11 +9,16 @@ module Asciidoctor::PDF::FormattedText
9
9
  text = fragment.text
10
10
  x = fragment.left
11
11
  y = fragment.baseline
12
- align = fragment.format_state[:align]
13
- if (align == :center || align == :right) && (gap_width = fragment.width - (document.width_of text)) != 0
14
- x += gap_width * (align == :center ? 0.5 : 1)
12
+ align = (format_state = fragment.format_state)[:align]
13
+ if align == :center || align == :right
14
+ gap_width = (format_state.key? :width) ?
15
+ fragment.width - (document.width_of text) :
16
+ (format_state[:border_offset] || 0) * 2
17
+ x += gap_width * (align == :center ? 0.5 : 1) if gap_width > 0
18
+ end
19
+ document.word_spacing fragment.word_spacing do
20
+ document.draw_text! text, at: [x, y], kerning: document.default_kerning?
15
21
  end
16
- document.draw_text! text, at: [x, y]
17
22
  fragment.conceal
18
23
  end
19
24
  end
@@ -36,8 +36,7 @@ module Asciidoctor::PDF::FormattedText
36
36
  end
37
37
  pdf.fill_color prev_fill_color
38
38
  end
39
- if (border_width = data[:border_width])
40
- border_color = data[:border_color]
39
+ if (border_width = data[:border_width]) && (border_color = data[:border_color])
41
40
  prev_stroke_color = pdf.stroke_color
42
41
  prev_line_width = pdf.line_width
43
42
  pdf.stroke_color border_color
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Asciidoctor
4
4
  module PDF
5
- VERSION = '2.0.4'
5
+ VERSION = '2.0.7'
6
6
  end
7
7
  end
@@ -1,18 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ autoload :Set, 'set'
4
+ autoload :StringIO, 'stringio'
5
+ autoload :Tempfile, 'tempfile'
6
+ require 'time' unless defined? Time.parse
3
7
  require_relative 'pdf/version'
4
8
  require 'asciidoctor'
5
9
  require 'prawn'
6
- # NOTE: patch float precision constant so prawn-table does not fail to arrange cells that span columns (see #1835)
7
- Prawn.send :remove_const, :FLOAT_PRECISION
8
- Prawn::FLOAT_PRECISION = 1e-3
9
10
  require 'prawn/templates'
10
- begin
11
- require 'prawn/gmagick'
12
- rescue LoadError # rubocop:disable Lint/SuppressedException
13
- end unless defined? GMagick::Image
14
- autoload :Set, 'set'
15
- require 'time' unless defined? Time.parse
16
11
  require_relative 'pdf/measurements'
17
12
  require_relative 'pdf/sanitizer'
18
13
  require_relative 'pdf/text_transformer'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciidoctor-pdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.4
4
+ version: 2.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Allen
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-05-25 00:00:00.000000000 Z
12
+ date: 2022-06-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: asciidoctor
@@ -258,8 +258,12 @@ files:
258
258
  - lib/asciidoctor/pdf/ext/core/string.rb
259
259
  - lib/asciidoctor/pdf/ext/pdf-core.rb
260
260
  - lib/asciidoctor/pdf/ext/pdf-core/page.rb
261
+ - lib/asciidoctor/pdf/ext/prawn-gmagick.rb
261
262
  - lib/asciidoctor/pdf/ext/prawn-svg.rb
263
+ - lib/asciidoctor/pdf/ext/prawn-svg/calculators/document_sizing.rb
264
+ - lib/asciidoctor/pdf/ext/prawn-svg/elements/image.rb
262
265
  - lib/asciidoctor/pdf/ext/prawn-svg/loaders/data.rb
266
+ - lib/asciidoctor/pdf/ext/prawn-svg/loaders/file.rb
263
267
  - lib/asciidoctor/pdf/ext/prawn-svg/loaders/web.rb
264
268
  - lib/asciidoctor/pdf/ext/prawn-svg/url_loader.rb
265
269
  - lib/asciidoctor/pdf/ext/prawn-table.rb