asciidoctor-pdf 2.0.5 → 2.0.8
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 +4 -4
- data/CHANGELOG.adoc +50 -0
- data/README.adoc +4 -4
- data/lib/asciidoctor/pdf/converter.rb +76 -29
- data/lib/asciidoctor/pdf/ext/prawn/document/column_box.rb +21 -6
- data/lib/asciidoctor/pdf/ext/prawn/extensions.rb +13 -9
- data/lib/asciidoctor/pdf/ext/prawn/images.rb +2 -19
- data/lib/asciidoctor/pdf/ext/prawn-gmagick.rb +18 -0
- data/lib/asciidoctor/pdf/ext/prawn-svg/calculators/document_sizing.rb +9 -0
- data/lib/asciidoctor/pdf/ext/prawn-svg/elements/image.rb +15 -0
- data/lib/asciidoctor/pdf/ext/prawn-svg/loaders/file.rb +22 -0
- data/lib/asciidoctor/pdf/ext/prawn-svg.rb +3 -0
- data/lib/asciidoctor/pdf/ext/prawn.rb +4 -0
- data/lib/asciidoctor/pdf/ext.rb +1 -0
- data/lib/asciidoctor/pdf/formatted_text/inline_image_arranger.rb +16 -8
- data/lib/asciidoctor/pdf/formatted_text/text_background_and_border_renderer.rb +1 -2
- data/lib/asciidoctor/pdf/theme_loader.rb +1 -1
- data/lib/asciidoctor/pdf/version.rb +1 -1
- data/lib/asciidoctor/pdf.rb +4 -9
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd47554913fab2e3f8002491a92c430e0dbfe48b9177705470ffa7c64155289b
|
4
|
+
data.tar.gz: 580c0c9e6a46e5614927f42c4ad309e303dd69681bf10ddb674241cd930e6b31
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 326e87435e664dde2e944b878d2c5c9a5b71cfd285da78115331a8cd14e20f2aaa0cb2b81779bc99ca8642df004ef03f60386a971e9176eb03d17755a9db951b
|
7
|
+
data.tar.gz: 7d7cd662e4bbe5df6d10c057e2f00a1a1c800f0e5a3e4f7731c94b657b0bf6ec51599e88d42dbd806a1e4bf991e54282c4efb820b0d39912ed34a74d25f89ff4
|
data/CHANGELOG.adoc
CHANGED
@@ -5,6 +5,56 @@
|
|
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.8 (2022-06-08) - @mojavelinux
|
9
|
+
|
10
|
+
Improvements::
|
11
|
+
|
12
|
+
* encapsulate logic to adjust column box inside float and dry run
|
13
|
+
* automatically set height on column box if not specified; update value automatically when reflowing margins
|
14
|
+
|
15
|
+
Bug Fixes::
|
16
|
+
|
17
|
+
* correctly compute value of to cursor on extent when column box starts below top of page (#2230)
|
18
|
+
* fix crash in `ColumnBox#move_past_bottom` when `:reflow_margins` option is not set
|
19
|
+
* fix x position of SVG when advanced to next column of column box
|
20
|
+
* `at_page_top?` should consider top of column box to be top of page
|
21
|
+
* prevent SVG image taller than column from being advanced to next column
|
22
|
+
* don't push section that follows index section in article to new page if last page of index does not extend to bottom of page
|
23
|
+
|
24
|
+
=== Details
|
25
|
+
|
26
|
+
{url-repo}/releases/tag/v2.0.8[git tag] | {url-repo}/compare/v2.0.7\...v2.0.8[full diff]
|
27
|
+
|
28
|
+
== 2.0.7 (2022-06-03) - @mojavelinux
|
29
|
+
|
30
|
+
Improvements::
|
31
|
+
|
32
|
+
* don't recommend prawn-gmagick if PNG or JPG is corrupt or incomplete
|
33
|
+
* add helper method to determine when to recommend the prawn-gmagick gem
|
34
|
+
|
35
|
+
Bug Fixes::
|
36
|
+
|
37
|
+
* fix crash when doctitle or section title with automatic ID contains inline image without explicit width (#2228)
|
38
|
+
* use prawn-gmagick, if available, to read raster image referenced by SVG (#2223)
|
39
|
+
* allow image path in SVG to refer to any location within Asciidoctor jail (no restriction if safe mode is unsafe) (#1941)
|
40
|
+
|
41
|
+
=== Details
|
42
|
+
|
43
|
+
{url-repo}/releases/tag/v2.0.7[git tag] | {url-repo}/compare/v2.0.6\...v2.0.7[full diff]
|
44
|
+
|
45
|
+
== 2.0.6 (2022-05-30) - @mojavelinux
|
46
|
+
|
47
|
+
Bug Fixes::
|
48
|
+
|
49
|
+
* indent content of collapsible block and apply bottom margin to match style of HTML output (#2219)
|
50
|
+
* patch prawn-gmagick to reread bit depth of a PNG image if it extracts the wrong value (#2216)
|
51
|
+
* interpret width of SVG correctly when width is defined in file using px units (#2215)
|
52
|
+
* don't crash if inline role defines border width but not border color
|
53
|
+
|
54
|
+
=== Details
|
55
|
+
|
56
|
+
{url-repo}/releases/tag/v2.0.6[git tag] | {url-repo}/compare/v2.0.5\...v2.0.6[full diff]
|
57
|
+
|
8
58
|
== 2.0.5 (2022-05-26) - @mojavelinux
|
9
59
|
|
10
60
|
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.
|
3
|
+
v2.0.8, 2022-06-08
|
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.
|
27
|
+
:release-version: 2.0.8
|
28
28
|
// URLs:
|
29
29
|
:url-gem: https://rubygems.org/gems/asciidoctor-pdf
|
30
30
|
:url-project: https://github.com/asciidoctor/asciidoctor-pdf
|
@@ -62,7 +62,7 @@ Asciidoctor PDF converts an AsciiDoc document directly to a PDF document.
|
|
62
62
|
The style and layout of the PDF are controlled by a dedicated theme file.
|
63
63
|
To the degree possible, Asciidoctor PDF supports all the features of AsciiDoc that are supported by Asciidoctor.
|
64
64
|
It also provides {url-project-docs}/features/[PDF-specific features].
|
65
|
-
However, there are {url-project-docs}/features/#limitations[certain
|
65
|
+
However, there are {url-project-docs}/features/#limitations[certain limitations] imposed by the PDF format and the PDF library this extension uses.
|
66
66
|
|
67
67
|
Asciidoctor PDF uses the Prawn gem and Prawn's extensions, such as prawn-svg and prawn-table, to generate a PDF document.
|
68
68
|
{url-prawn}[Prawn] is a general purpose PDF generator for Ruby that features high-level APIs for common needs like setting up the page and inserting images and low-level APIs for positioning and rendering text and graphics.
|
@@ -182,7 +182,7 @@ Asciidoctor creates the output file in the same directory as the input file by d
|
|
182
182
|
Open the [.path]_basic-example.pdf_ file with a PDF viewer to see the result.
|
183
183
|
|
184
184
|
.Example PDF document rendered in a PDF viewer
|
185
|
-
image::docs/modules/ROOT/images/basic-example-pdf-screenshot.png[Screenshot of PDF document,960,
|
185
|
+
image::docs/modules/ROOT/images/basic-example-pdf-screenshot.png[Screenshot of PDF document,960,pdfwidth=100%]
|
186
186
|
|
187
187
|
For more information about how to use Asciidoctor PDF and PDF-specific AsciiDoc syntax, see the {url-project-docs}/[Asciidoctor PDF documentation].
|
188
188
|
|
@@ -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
|
-
|
155
|
+
node.inline? ? result : self
|
157
156
|
end
|
158
157
|
|
159
158
|
def convert_document doc
|
@@ -163,7 +162,6 @@ module Asciidoctor
|
|
163
162
|
doc.attributes['outline'] = '' unless (doc.attribute_locked? 'outline') || ((doc.instance_variable_get :@attributes_modified).include? 'outline')
|
164
163
|
doc.attributes['outline-title'] = '' unless (doc.attribute_locked? 'outline-title') || ((doc.instance_variable_get :@attributes_modified).include? 'outline-title')
|
165
164
|
doc.attributes['pagenums'] = '' unless (doc.attribute_locked? 'pagenums') || ((doc.instance_variable_get :@attributes_modified).include? 'pagenums')
|
166
|
-
#assign_missing_section_ids doc
|
167
165
|
|
168
166
|
on_page_create(&(method :init_page))
|
169
167
|
|
@@ -339,7 +337,11 @@ module Asciidoctor
|
|
339
337
|
#@page_opts = { size: pdf_opts[:page_size], layout: pdf_opts[:page_layout] }
|
340
338
|
((::Prawn::Document.instance_method :initialize).bind self).call pdf_opts
|
341
339
|
renderer.min_version (@pdf_version = PDFVersions[doc.attr 'pdf-version'])
|
342
|
-
@
|
340
|
+
@tmp_files ||= {}
|
341
|
+
@allow_uri_read = doc.attr? 'allow-uri-read'
|
342
|
+
@cache_uri = doc.attr? 'cache-uri'
|
343
|
+
@jail_dir = doc.safe < ::Asciidoctor::SafeMode::SAFE ? nil : doc.base_dir
|
344
|
+
@media ||= doc.attr 'media', 'screen'
|
343
345
|
@page_margin_by_side = { recto: (page_margin_recto = page_margin), verso: (page_margin_verso = page_margin), cover: page_margin }
|
344
346
|
case doc.attr 'pdf-folio-placement', (@media == 'prepress' ? 'physical' : 'virtual')
|
345
347
|
when 'physical'
|
@@ -364,13 +366,6 @@ module Asciidoctor
|
|
364
366
|
else
|
365
367
|
@ppbook = nil
|
366
368
|
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
369
|
if (bg_image = resolve_background_image doc, theme, 'page-background-image')&.first
|
375
370
|
@page_bg_image = { verso: bg_image, recto: bg_image }
|
376
371
|
else
|
@@ -383,6 +378,10 @@ module Asciidoctor
|
|
383
378
|
@page_bg_image[:recto] = bg_image[0] && bg_image
|
384
379
|
end
|
385
380
|
@page_bg_color = resolve_theme_color :page_background_color, 'FFFFFF'
|
381
|
+
# QUESTION: should ThemeLoader handle registering fonts instead?
|
382
|
+
register_fonts theme.font_catalog, ((doc.attr 'pdf-fontsdir')&.sub '{docdir}', (doc.attr 'docdir')) || 'GEM_FONTS_DIR'
|
383
|
+
default_kerning theme.base_font_kerning != 'none'
|
384
|
+
@fallback_fonts = Array theme.font_fallbacks
|
386
385
|
@root_font_size = theme.base_font_size
|
387
386
|
@font_scale = 1
|
388
387
|
@font_color = theme.base_font_color
|
@@ -703,6 +702,7 @@ module Asciidoctor
|
|
703
702
|
def convert_index_section node
|
704
703
|
space_needed_for_category = @theme.description_list_term_spacing + (2 * (height_of_typeset_text 'A'))
|
705
704
|
pagenum_sequence_style = node.document.attr 'index-pagenum-sequence-style'
|
705
|
+
end_cursor = nil
|
706
706
|
column_box [0, cursor], columns: @theme.index_columns, width: bounds.width, reflow_margins: true, spacer: @theme.index_column_gap do
|
707
707
|
@index.categories.each do |category|
|
708
708
|
bounds.move_past_bottom if space_needed_for_category > cursor
|
@@ -714,7 +714,10 @@ module Asciidoctor
|
|
714
714
|
category.terms.each {|term| convert_index_list_item term, pagenum_sequence_style }
|
715
715
|
@theme.prose_margin_bottom > cursor ? bounds.move_past_bottom : (move_down @theme.prose_margin_bottom)
|
716
716
|
end
|
717
|
+
end_cursor = cursor if bounds.current_column == 0
|
717
718
|
end
|
719
|
+
# Q: could we move this logic into column_box?
|
720
|
+
move_cursor_to end_cursor if end_cursor
|
718
721
|
nil
|
719
722
|
end
|
720
723
|
|
@@ -939,7 +942,7 @@ module Asciidoctor
|
|
939
942
|
height: label_height,
|
940
943
|
fallback_font_name: fallback_svg_font_name,
|
941
944
|
enable_web_requests: allow_uri_read ? (method :load_open_uri).to_proc : false,
|
942
|
-
enable_file_requests_with_root: (::File.dirname icon_path),
|
945
|
+
enable_file_requests_with_root: { base: (::File.dirname icon_path), root: @jail_dir },
|
943
946
|
cache_images: cache_uri
|
944
947
|
svg_obj.resize height: label_height if svg_obj.document.sizing.output_height > label_height
|
945
948
|
svg_obj.draw
|
@@ -1167,8 +1170,26 @@ module Asciidoctor
|
|
1167
1170
|
alias convert_literal convert_code
|
1168
1171
|
alias convert_listing_or_literal convert_code
|
1169
1172
|
|
1173
|
+
def convert_collapsible node
|
1174
|
+
id = node.id
|
1175
|
+
title = (collapsible_marker = %(\u25bc )) + (node.title? ? node.title : 'Details')
|
1176
|
+
indent_by = theme_font(:caption) { rendered_width_of_string collapsible_marker }
|
1177
|
+
if !at_page_top? && (id || (node.option? 'unbreakable'))
|
1178
|
+
arrange_block node do
|
1179
|
+
add_dest_for_block node if id
|
1180
|
+
tare_first_page_content_stream { ink_caption title }
|
1181
|
+
indent(indent_by) { traverse node }
|
1182
|
+
end
|
1183
|
+
else
|
1184
|
+
add_dest_for_block node if id
|
1185
|
+
tare_first_page_content_stream { ink_caption title }
|
1186
|
+
indent(indent_by) { traverse node }
|
1187
|
+
end
|
1188
|
+
theme_margin :block, :bottom, (next_enclosed_block node)
|
1189
|
+
end
|
1190
|
+
|
1170
1191
|
def convert_example node
|
1171
|
-
return
|
1192
|
+
return convert_collapsible node if node.option? 'collapsible'
|
1172
1193
|
caption_bottom = @theme.example_caption_end&.to_sym == :bottom
|
1173
1194
|
arrange_block node do |extent|
|
1174
1195
|
add_dest_for_block node if node.id
|
@@ -1193,14 +1214,12 @@ module Asciidoctor
|
|
1193
1214
|
if !at_page_top? && (has_title || id || (node.option? 'unbreakable'))
|
1194
1215
|
arrange_block node do
|
1195
1216
|
add_dest_for_block node if id
|
1196
|
-
tare_first_page_content_stream
|
1197
|
-
node.context == :example ? (ink_caption %(\u25bc #{node.title})) : (ink_caption node, labeled: false)
|
1198
|
-
end if has_title
|
1217
|
+
tare_first_page_content_stream { ink_caption node, labeled: false } if has_title
|
1199
1218
|
traverse node
|
1200
1219
|
end
|
1201
1220
|
else
|
1202
1221
|
add_dest_for_block node if id
|
1203
|
-
|
1222
|
+
ink_caption node, labeled: false if has_title
|
1204
1223
|
traverse node
|
1205
1224
|
end
|
1206
1225
|
end
|
@@ -1718,7 +1737,7 @@ module Asciidoctor
|
|
1718
1737
|
file_request_root = false
|
1719
1738
|
else
|
1720
1739
|
svg_data = ::File.read image_path, mode: 'r:UTF-8'
|
1721
|
-
file_request_root = ::File.dirname image_path
|
1740
|
+
file_request_root = { base: (::File.dirname image_path), root: @jail_dir }
|
1722
1741
|
end
|
1723
1742
|
svg_obj = ::Prawn::SVG::Interface.new svg_data, self,
|
1724
1743
|
position: alignment,
|
@@ -1736,6 +1755,7 @@ module Asciidoctor
|
|
1736
1755
|
if (rendered_h = svg_size.output_height) > (available_h = cursor - caption_h)
|
1737
1756
|
unless pinned || at_page_top?
|
1738
1757
|
advance_page
|
1758
|
+
(svg_obj.options[:at] = svg_obj.position)[0] += bounds.left if ColumnBox === bounds
|
1739
1759
|
available_h = cursor - caption_h
|
1740
1760
|
end
|
1741
1761
|
rendered_w = (svg_obj.resize height: (rendered_h = available_h)).output_width if rendered_h > available_h
|
@@ -1798,7 +1818,7 @@ module Asciidoctor
|
|
1798
1818
|
end
|
1799
1819
|
rescue => e
|
1800
1820
|
raise if ::StopIteration === e
|
1801
|
-
on_image_error :exception, node, target, (opts.merge align: alignment, message: %(could not embed image: #{image_path}; #{e.message}#{
|
1821
|
+
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
1822
|
end
|
1803
1823
|
end
|
1804
1824
|
|
@@ -2492,14 +2512,19 @@ module Asciidoctor
|
|
2492
2512
|
# NOTE: an image with a data URI is handled using a temporary file
|
2493
2513
|
elsif (image_path = resolve_image_path node, target, image_format)
|
2494
2514
|
if ::File.readable? image_path
|
2515
|
+
class_attr = (role = node.role) ? %( class="#{role}") : ''
|
2516
|
+
fit_attr = (fit = node.attr 'fit') ? %( fit="#{fit}") : ''
|
2495
2517
|
if (width = resolve_explicit_width node.attributes)
|
2496
|
-
|
2518
|
+
if node.parent.context == :table_cell && ::String === width && (width.end_with? '%')
|
2519
|
+
width += (intrinsic_image_dimensions image_path, image_format)[:width].to_s
|
2520
|
+
end
|
2521
|
+
width_attr = %( width="#{width}")
|
2522
|
+
elsif state # check that converter is initialized
|
2523
|
+
width_attr = %( width="#{(intrinsic_image_dimensions image_path, image_format)[:width]}")
|
2497
2524
|
else
|
2498
|
-
|
2525
|
+
width_attr = ' width="auto"' # defer operation until arranger runs
|
2499
2526
|
end
|
2500
|
-
|
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}>)
|
2527
|
+
img = %(<img src="#{image_path}" format="#{image_format}" alt="#{encode_quotes node.attr 'alt'}"#{width_attr}#{class_attr}#{fit_attr}>)
|
2503
2528
|
else
|
2504
2529
|
log :warn, %(image to embed not found or not readable: #{image_path})
|
2505
2530
|
img = %([#{node.attr 'alt'}])
|
@@ -3001,7 +3026,7 @@ module Asciidoctor
|
|
3001
3026
|
end
|
3002
3027
|
end
|
3003
3028
|
end
|
3004
|
-
theme_font_cascade [
|
3029
|
+
theme_font_cascade ['caption', category_caption] do
|
3005
3030
|
if ((opts.delete :end) || (opts.delete :side) || :top) == :top
|
3006
3031
|
margin = { top: caption_margin_outside, bottom: caption_margin_inside }
|
3007
3032
|
else
|
@@ -3825,6 +3850,27 @@ module Asciidoctor
|
|
3825
3850
|
end
|
3826
3851
|
end
|
3827
3852
|
|
3853
|
+
# Retrieve the intrinsic image dimensions for the specified path in pt.
|
3854
|
+
#
|
3855
|
+
# Returns a Hash containing :width and :height keys that map to the image's
|
3856
|
+
# intrinsic width and height values (in pt).
|
3857
|
+
def intrinsic_image_dimensions path, format
|
3858
|
+
if format == 'svg'
|
3859
|
+
# NOTE: prawn-svg automatically converts intrinsic width and height to pt
|
3860
|
+
img_obj = ::Prawn::SVG::Interface.new (::File.read path, mode: 'r:UTF-8'), self, {}
|
3861
|
+
img_size = img_obj.document.sizing
|
3862
|
+
{ width: img_size.output_width, height: img_size.output_height }
|
3863
|
+
else
|
3864
|
+
# NOTE: build_image_object caches image data previously loaded
|
3865
|
+
# NOTE: build_image_object computes intrinsic width and height in px
|
3866
|
+
_, img_size = ::File.open(path, 'rb') {|fd| build_image_object fd }
|
3867
|
+
{ width: (to_pt img_size.width, :px), height: (to_pt img_size.height, :px) }
|
3868
|
+
end
|
3869
|
+
rescue
|
3870
|
+
# NOTE: image can't be read, so it won't be used anyway
|
3871
|
+
{ width: 0, height: 0 }
|
3872
|
+
end
|
3873
|
+
|
3828
3874
|
# Sends the specified message to the log unless this method is called from the scratch document
|
3829
3875
|
def log severity, message = nil, &block
|
3830
3876
|
logger.send severity, message, &block unless scratch?
|
@@ -4033,7 +4079,7 @@ module Asciidoctor
|
|
4033
4079
|
def resolve_image_options image_path, image_format, image_attrs, opts = {}
|
4034
4080
|
if image_format == 'svg'
|
4035
4081
|
image_opts = {
|
4036
|
-
enable_file_requests_with_root: (::File.dirname image_path),
|
4082
|
+
enable_file_requests_with_root: { base: (::File.dirname image_path), root: @jail_dir },
|
4037
4083
|
enable_web_requests: allow_uri_read ? (method :load_open_uri).to_proc : false,
|
4038
4084
|
cache_images: cache_uri,
|
4039
4085
|
fallback_font_name: fallback_svg_font_name,
|
@@ -4120,6 +4166,7 @@ module Asciidoctor
|
|
4120
4166
|
else
|
4121
4167
|
imagesdir = relative_to
|
4122
4168
|
end
|
4169
|
+
@tmp_files ||= {}
|
4123
4170
|
# NOTE: base64 logic currently used for inline images
|
4124
4171
|
if ::Base64 === image_path
|
4125
4172
|
return @tmp_files[image_path] if @tmp_files.key? image_path
|
@@ -4346,7 +4393,7 @@ module Asciidoctor
|
|
4346
4393
|
end
|
4347
4394
|
|
4348
4395
|
def theme_font_cascade categories, &block
|
4349
|
-
if ::Array === (category = (categories = categories.
|
4396
|
+
if ::Array === (category = (categories = categories.uniq).shift)
|
4350
4397
|
category, opts = category
|
4351
4398
|
else
|
4352
4399
|
opts = {}
|
@@ -1,20 +1,35 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
Prawn::Document::ColumnBox.prepend (Module.new do
|
4
|
-
|
5
|
-
stretchy? ? @parent.absolute_bottom : super
|
6
|
-
end
|
4
|
+
attr_accessor :current_column
|
7
5
|
|
8
6
|
def move_past_bottom
|
9
7
|
(doc = @document).y = @y
|
10
8
|
return if (@current_column = (@current_column + 1) % @columns) > 0
|
11
|
-
|
9
|
+
par = @parent
|
10
|
+
if (reset_y = @reflow_margins) && (reset_y == true || reset_y > doc.page_number)
|
11
|
+
@y = par.absolute_top
|
12
|
+
@height = par.height unless stretchy?
|
13
|
+
end
|
12
14
|
initial_margins = doc.page.margins
|
13
15
|
par.move_past_bottom
|
14
16
|
if doc.page.margins != initial_margins
|
15
|
-
doc.bounds = self.class.new doc, par, (margin_box = doc.margin_box).
|
16
|
-
columns: @columns, reflow_margins:
|
17
|
+
doc.bounds = self.class.new doc, par, [(margin_box = doc.margin_box).absolute_left, @y],
|
18
|
+
columns: @columns, reflow_margins: @reflow_margins, spacer: @spacer, width: margin_box.width, height: @height
|
19
|
+
end
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
# Rearranges the column box into a single column, where the original columns are in a single file. Used
|
24
|
+
# for the purpose of computing the extent of content in a scratch document.
|
25
|
+
def single_file
|
26
|
+
if @reflow_margins && @parent.absolute_top > @y && @columns > @current_column + 1
|
27
|
+
# defer reflow margins until all columns on current page have been exhausted
|
28
|
+
@reflow_margins = @document.page_number + (@columns - @current_column)
|
17
29
|
end
|
30
|
+
@width = bare_column_width
|
31
|
+
@columns = 1
|
32
|
+
@current_column = 0
|
18
33
|
nil
|
19
34
|
end
|
20
35
|
end)
|
@@ -251,16 +251,17 @@ module Asciidoctor
|
|
251
251
|
# Returns whether the cursor is at the top of the page (i.e., margin box).
|
252
252
|
#
|
253
253
|
def at_page_top?
|
254
|
-
@y == @margin_box.absolute_top
|
254
|
+
@y == (ColumnBox === bounds ? bounds : @margin_box).absolute_top
|
255
255
|
end
|
256
256
|
|
257
257
|
# Prevents at_page_top? from returning true while yielding to the specified block.
|
258
258
|
#
|
259
259
|
def conceal_page_top
|
260
|
-
|
260
|
+
old_top = (outer_bounds = ColumnBox === bounds ? bounds : @margin_box).absolute_top
|
261
|
+
outer_bounds.instance_variable_set :@y, old_top + 0.0001
|
261
262
|
yield
|
262
263
|
ensure
|
263
|
-
|
264
|
+
outer_bounds.instance_variable_set :@y, old_top
|
264
265
|
end
|
265
266
|
|
266
267
|
# Returns whether the current page is the last page in the document.
|
@@ -560,11 +561,11 @@ module Asciidoctor
|
|
560
561
|
def float
|
561
562
|
original_page_number = page_number
|
562
563
|
original_y = y
|
563
|
-
original_column = bounds.
|
564
|
+
original_column = bounds.current_column if ColumnBox === bounds
|
564
565
|
yield
|
565
566
|
go_to_page original_page_number unless page_number == original_page_number
|
566
567
|
self.y = original_y
|
567
|
-
bounds.
|
568
|
+
bounds.current_column = original_column if original_column
|
568
569
|
end
|
569
570
|
|
570
571
|
# Short-circuits the call to the built-in move_up operation
|
@@ -721,6 +722,12 @@ module Asciidoctor
|
|
721
722
|
end
|
722
723
|
end
|
723
724
|
|
725
|
+
# Wraps the column_box method and automatically sets the height unless the :height option is specified.
|
726
|
+
def column_box point, options, &block
|
727
|
+
options[:height] = cursor unless options.key? :height
|
728
|
+
super
|
729
|
+
end
|
730
|
+
|
724
731
|
# A flowing version of bounding_box. If the content runs to another page, the cursor starts at
|
725
732
|
# the top of the page instead of from the original cursor position. Similar to span, except
|
726
733
|
# the :position option is limited to a numeric value and additional options are passed through
|
@@ -1146,10 +1153,7 @@ module Asciidoctor
|
|
1146
1153
|
scratch_pdf.bounds = bounds.dup.tap do |bounds_copy|
|
1147
1154
|
bounds_copy.instance_variable_set :@document, scratch_pdf
|
1148
1155
|
bounds_copy.instance_variable_set :@parent, saved_bounds
|
1149
|
-
if ColumnBox === bounds_copy
|
1150
|
-
bounds_copy.instance_variable_set :@width, bounds_copy.bare_column_width
|
1151
|
-
bounds_copy.instance_variable_set :@current_column, (bounds_copy.instance_variable_set :@columns, 1) - 1
|
1152
|
-
end
|
1156
|
+
bounds_copy.single_file if ColumnBox === bounds_copy
|
1153
1157
|
end
|
1154
1158
|
scratch_pdf.move_cursor_to cursor unless (scratch_start_at_top = keep_together || pages_advanced > 0 || at_page_top?)
|
1155
1159
|
scratch_start_cursor = scratch_pdf.cursor
|
@@ -33,25 +33,8 @@ module Asciidoctor
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
|
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'
|
data/lib/asciidoctor/pdf/ext.rb
CHANGED
@@ -48,10 +48,11 @@ module Asciidoctor::PDF::FormattedText
|
|
48
48
|
drop = scratch
|
49
49
|
end
|
50
50
|
image_path = fragment[:image_path]
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
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
|
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
|
-
|
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}#{
|
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
|
@@ -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
|
@@ -69,7 +69,7 @@ module Asciidoctor
|
|
69
69
|
# NOTE: base theme is loaded "as is" (no post-processing)
|
70
70
|
def self.load_base_theme
|
71
71
|
::File.open BaseThemePath, mode: 'r:UTF-8' do |io|
|
72
|
-
(::OpenStruct.new ::YAML.safe_load io,
|
72
|
+
(::OpenStruct.new ::YAML.safe_load io, filename: BaseThemePath).tap {|theme| theme.__dir__ = ThemesDir }
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
data/lib/asciidoctor/pdf.rb
CHANGED
@@ -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
|
+
version: 2.0.8
|
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-
|
12
|
+
date: 2022-06-08 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
|