asciidoctor-pdf 2.0.6 → 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: 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