asciidoctor-pdf 2.0.5 → 2.0.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|