asciidoctor-pdf 2.0.6 → 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: be0ccb9b1f50f98f904f500c7b2bf0118157714825e28739ab80df39ff101bf9
4
- data.tar.gz: 1ce0fafde09b3e41ad86782397e0034bc8bd6f82d06dff01346bf055ead214d0
3
+ metadata.gz: f836f6c86c31a3bbd792bba4608f397422361bcc5b297355eccab266a3a5ac0b
4
+ data.tar.gz: b31b434d0d7bede025b4f3c25e71a518f120a66840dfb7df72308d17fda9bd8e
5
5
  SHA512:
6
- metadata.gz: ea8d2b78a501da0ce41cc9dabf88f19fe1926262725661012c4f5f00ffc10f34e1a479ca4cf6b66a6601d4f9f2ada928fc23eb0cb422b391503955f21b072a8d
7
- data.tar.gz: 3916e7d631167b57babd839b9f352932ca3df05022a4487195a2d8c8ee07165bdccb0127cd447d1e525f23a6bd2ef88d7710ad63075ec70c5763e5e7b8f6a237
6
+ metadata.gz: 84899cfb74ce8ef2c97111d585e73529318c3f0a44756f75674338f58c1d46693925fe1f9d42b9666f07d8a1bed68f606ec3ec2b664816d0c92998494e90a39a
7
+ data.tar.gz: a50053c502cf572929c49802208e18faa9f1e5bf0a2f3e47972c3863fafa3c43e157425e7b3c5a1ad12cc0e301d8e461a108907e48f5b80aaa0f05938dc2e6a2
data/CHANGELOG.adoc CHANGED
@@ -5,6 +5,23 @@
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
+
8
25
  == 2.0.6 (2022-05-30) - @mojavelinux
9
26
 
10
27
  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.6, 2022-05-30
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.6
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
@@ -20,6 +20,8 @@ module Asciidoctor
20
20
 
21
21
  attr_reader :cache_uri
22
22
 
23
+ attr_reader :jail_dir
24
+
23
25
  attr_accessor :font_color
24
26
 
25
27
  attr_accessor :font_scale
@@ -150,7 +152,7 @@ module Asciidoctor
150
152
  log :warn, %(missing convert handler for #{name} node in #{@backend} backend)
151
153
  end
152
154
  # NOTE: inline node handlers generate HTML-like strings; all other handlers write directly to the PDF object
153
- ::Asciidoctor::Inline === node ? result : self
155
+ node.inline? ? result : self
154
156
  end
155
157
 
156
158
  def convert_document doc
@@ -336,7 +338,11 @@ module Asciidoctor
336
338
  #@page_opts = { size: pdf_opts[:page_size], layout: pdf_opts[:page_layout] }
337
339
  ((::Prawn::Document.instance_method :initialize).bind self).call pdf_opts
338
340
  renderer.min_version (@pdf_version = PDFVersions[doc.attr 'pdf-version'])
339
- @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'
340
346
  @page_margin_by_side = { recto: (page_margin_recto = page_margin), verso: (page_margin_verso = page_margin), cover: page_margin }
341
347
  case doc.attr 'pdf-folio-placement', (@media == 'prepress' ? 'physical' : 'virtual')
342
348
  when 'physical'
@@ -361,13 +367,6 @@ module Asciidoctor
361
367
  else
362
368
  @ppbook = nil
363
369
  end
364
- # QUESTION: should ThemeLoader handle registering fonts instead?
365
- register_fonts theme.font_catalog, ((doc.attr 'pdf-fontsdir')&.sub '{docdir}', (doc.attr 'docdir')) || 'GEM_FONTS_DIR'
366
- default_kerning theme.base_font_kerning != 'none'
367
- @fallback_fonts = Array theme.font_fallbacks
368
- @allow_uri_read = doc.attr? 'allow-uri-read'
369
- @cache_uri = doc.attr? 'cache-uri'
370
- @tmp_files = {}
371
370
  if (bg_image = resolve_background_image doc, theme, 'page-background-image')&.first
372
371
  @page_bg_image = { verso: bg_image, recto: bg_image }
373
372
  else
@@ -380,6 +379,10 @@ module Asciidoctor
380
379
  @page_bg_image[:recto] = bg_image[0] && bg_image
381
380
  end
382
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
383
386
  @root_font_size = theme.base_font_size
384
387
  @font_scale = 1
385
388
  @font_color = theme.base_font_color
@@ -936,7 +939,7 @@ module Asciidoctor
936
939
  height: label_height,
937
940
  fallback_font_name: fallback_svg_font_name,
938
941
  enable_web_requests: allow_uri_read ? (method :load_open_uri).to_proc : false,
939
- enable_file_requests_with_root: (::File.dirname icon_path),
942
+ enable_file_requests_with_root: { base: (::File.dirname icon_path), root: @jail_dir },
940
943
  cache_images: cache_uri
941
944
  svg_obj.resize height: label_height if svg_obj.document.sizing.output_height > label_height
942
945
  svg_obj.draw
@@ -1731,7 +1734,7 @@ module Asciidoctor
1731
1734
  file_request_root = false
1732
1735
  else
1733
1736
  svg_data = ::File.read image_path, mode: 'r:UTF-8'
1734
- file_request_root = ::File.dirname image_path
1737
+ file_request_root = { base: (::File.dirname image_path), root: @jail_dir }
1735
1738
  end
1736
1739
  svg_obj = ::Prawn::SVG::Interface.new svg_data, self,
1737
1740
  position: alignment,
@@ -1811,7 +1814,7 @@ module Asciidoctor
1811
1814
  end
1812
1815
  rescue => e
1813
1816
  raise if ::StopIteration === e
1814
- 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) : ''}))
1815
1818
  end
1816
1819
  end
1817
1820
 
@@ -2505,14 +2508,19 @@ module Asciidoctor
2505
2508
  # NOTE: an image with a data URI is handled using a temporary file
2506
2509
  elsif (image_path = resolve_image_path node, target, image_format)
2507
2510
  if ::File.readable? image_path
2511
+ class_attr = (role = node.role) ? %( class="#{role}") : ''
2512
+ fit_attr = (fit = node.attr 'fit') ? %( fit="#{fit}") : ''
2508
2513
  if (width = resolve_explicit_width node.attributes)
2509
- 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]}")
2510
2520
  else
2511
- width = (intrinsic_image_dimensions image_path, image_format)[:width]
2521
+ width_attr = ' width="auto"' # defer operation until arranger runs
2512
2522
  end
2513
- class_attr = (role = node.role) ? %( class="#{role}") : ''
2514
- fit_attr = (fit = node.attr 'fit') ? %( fit="#{fit}") : ''
2515
- 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}>)
2516
2524
  else
2517
2525
  log :warn, %(image to embed not found or not readable: #{image_path})
2518
2526
  img = %([#{node.attr 'alt'}&#93;)
@@ -3838,6 +3846,27 @@ module Asciidoctor
3838
3846
  end
3839
3847
  end
3840
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
+
3841
3870
  # Sends the specified message to the log unless this method is called from the scratch document
3842
3871
  def log severity, message = nil, &block
3843
3872
  logger.send severity, message, &block unless scratch?
@@ -4046,7 +4075,7 @@ module Asciidoctor
4046
4075
  def resolve_image_options image_path, image_format, image_attrs, opts = {}
4047
4076
  if image_format == 'svg'
4048
4077
  image_opts = {
4049
- enable_file_requests_with_root: (::File.dirname image_path),
4078
+ enable_file_requests_with_root: { base: (::File.dirname image_path), root: @jail_dir },
4050
4079
  enable_web_requests: allow_uri_read ? (method :load_open_uri).to_proc : false,
4051
4080
  cache_images: cache_uri,
4052
4081
  fallback_font_name: fallback_svg_font_name,
@@ -4133,6 +4162,7 @@ module Asciidoctor
4133
4162
  else
4134
4163
  imagesdir = relative_to
4135
4164
  end
4165
+ @tmp_files ||= {}
4136
4166
  # NOTE: base64 logic currently used for inline images
4137
4167
  if ::Base64 === image_path
4138
4168
  return @tmp_files[image_path] if @tmp_files.key? image_path
@@ -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,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)
@@ -2,7 +2,9 @@
2
2
 
3
3
  require 'prawn-svg'
4
4
  require_relative 'prawn-svg/calculators/document_sizing'
5
+ require_relative 'prawn-svg/elements/image'
5
6
  require_relative 'prawn-svg/loaders/data'
7
+ require_relative 'prawn-svg/loaders/file'
6
8
  require_relative 'prawn-svg/loaders/web'
7
9
  require_relative 'prawn-svg/url_loader'
8
10
  # NOTE: disable system fonts since they're non-portable
@@ -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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Asciidoctor
4
4
  module PDF
5
- VERSION = '2.0.6'
5
+ VERSION = '2.0.7'
6
6
  end
7
7
  end
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.6
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-30 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
@@ -261,7 +261,9 @@ files:
261
261
  - lib/asciidoctor/pdf/ext/prawn-gmagick.rb
262
262
  - lib/asciidoctor/pdf/ext/prawn-svg.rb
263
263
  - lib/asciidoctor/pdf/ext/prawn-svg/calculators/document_sizing.rb
264
+ - lib/asciidoctor/pdf/ext/prawn-svg/elements/image.rb
264
265
  - lib/asciidoctor/pdf/ext/prawn-svg/loaders/data.rb
266
+ - lib/asciidoctor/pdf/ext/prawn-svg/loaders/file.rb
265
267
  - lib/asciidoctor/pdf/ext/prawn-svg/loaders/web.rb
266
268
  - lib/asciidoctor/pdf/ext/prawn-svg/url_loader.rb
267
269
  - lib/asciidoctor/pdf/ext/prawn-table.rb