asciidoctor-pdf 2.0.4 → 2.0.7

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 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