asciidoctor-pdf 2.0.4 → 2.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +41 -0
- data/README.adoc +2 -2
- data/lib/asciidoctor/pdf/converter.rb +72 -29
- data/lib/asciidoctor/pdf/ext/prawn/extensions.rb +2 -2
- data/lib/asciidoctor/pdf/ext/prawn/formatted_text/fragment.rb +6 -2
- 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/inline_text_aligner.rb +9 -4
- data/lib/asciidoctor/pdf/formatted_text/text_background_and_border_renderer.rb +1 -2
- 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: f836f6c86c31a3bbd792bba4608f397422361bcc5b297355eccab266a3a5ac0b
|
4
|
+
data.tar.gz: b31b434d0d7bede025b4f3c25e71a518f120a66840dfb7df72308d17fda9bd8e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84899cfb74ce8ef2c97111d585e73529318c3f0a44756f75674338f58c1d46693925fe1f9d42b9666f07d8a1bed68f606ec3ec2b664816d0c92998494e90a39a
|
7
|
+
data.tar.gz: a50053c502cf572929c49802208e18faa9f1e5bf0a2f3e47972c3863fafa3c43e157425e7b3c5a1ad12cc0e301d8e461a108907e48f5b80aaa0f05938dc2e6a2
|
data/CHANGELOG.adoc
CHANGED
@@ -5,6 +5,47 @@
|
|
5
5
|
This document provides a high-level view of the changes to the {project-name} by release.
|
6
6
|
For a detailed view of what has changed, refer to the {url-repo}/commits/main[commit history] on GitHub.
|
7
7
|
|
8
|
+
== 2.0.7 (2022-06-03) - @mojavelinux
|
9
|
+
|
10
|
+
Improvements::
|
11
|
+
|
12
|
+
* don't recommend prawn-gmagick if PNG or JPG is corrupt or incomplete
|
13
|
+
* add helper method to determine when to recommend the prawn-gmagick gem
|
14
|
+
|
15
|
+
Bug Fixes::
|
16
|
+
|
17
|
+
* fix crash when doctitle or section title with automatic ID contains inline image without explicit width (#2228)
|
18
|
+
* use prawn-gmagick, if available, to read raster image referenced by SVG (#2223)
|
19
|
+
* allow image path in SVG to refer to any location within Asciidoctor jail (no restriction if safe mode is unsafe) (#1941)
|
20
|
+
|
21
|
+
=== Details
|
22
|
+
|
23
|
+
{url-repo}/releases/tag/v2.0.7[git tag] | {url-repo}/compare/v2.0.6\...v2.0.7[full diff]
|
24
|
+
|
25
|
+
== 2.0.6 (2022-05-30) - @mojavelinux
|
26
|
+
|
27
|
+
Bug Fixes::
|
28
|
+
|
29
|
+
* indent content of collapsible block and apply bottom margin to match style of HTML output (#2219)
|
30
|
+
* patch prawn-gmagick to reread bit depth of a PNG image if it extracts the wrong value (#2216)
|
31
|
+
* interpret width of SVG correctly when width is defined in file using px units (#2215)
|
32
|
+
* don't crash if inline role defines border width but not border color
|
33
|
+
|
34
|
+
=== Details
|
35
|
+
|
36
|
+
{url-repo}/releases/tag/v2.0.6[git tag] | {url-repo}/compare/v2.0.5\...v2.0.6[full diff]
|
37
|
+
|
38
|
+
== 2.0.5 (2022-05-26) - @mojavelinux
|
39
|
+
|
40
|
+
Bug Fixes::
|
41
|
+
|
42
|
+
* do not filter TOC entries without an ID when computing the TOC extent (#2210)
|
43
|
+
* fix width of multi-word phrase with background and border offset (#2059)
|
44
|
+
|
45
|
+
=== Details
|
46
|
+
|
47
|
+
{url-repo}/releases/tag/v2.0.5[git tag] | {url-repo}/compare/v2.0.4\...v2.0.5[full diff]
|
48
|
+
|
8
49
|
== 2.0.4 (2022-05-25) - @mojavelinux
|
9
50
|
|
10
51
|
Bug Fixes::
|
data/README.adoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= Asciidoctor PDF: A native PDF converter for AsciiDoc
|
2
2
|
Dan Allen <https://github.com/mojavelinux[@mojavelinux]>; Sarah White <https://github.com/graphitefriction[@graphitefriction]>
|
3
|
-
v2.0.
|
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.
|
27
|
+
:release-version: 2.0.7
|
28
28
|
// URLs:
|
29
29
|
:url-gem: https://rubygems.org/gems/asciidoctor-pdf
|
30
30
|
:url-project: https://github.com/asciidoctor/asciidoctor-pdf
|
@@ -6,9 +6,6 @@ require_relative 'pdfmark'
|
|
6
6
|
require_relative 'roman_numeral'
|
7
7
|
require_relative 'section_info_by_page'
|
8
8
|
|
9
|
-
autoload :StringIO, 'stringio'
|
10
|
-
autoload :Tempfile, 'tempfile'
|
11
|
-
|
12
9
|
module Asciidoctor
|
13
10
|
module PDF
|
14
11
|
class Converter < ::Prawn::Document
|
@@ -23,6 +20,8 @@ module Asciidoctor
|
|
23
20
|
|
24
21
|
attr_reader :cache_uri
|
25
22
|
|
23
|
+
attr_reader :jail_dir
|
24
|
+
|
26
25
|
attr_accessor :font_color
|
27
26
|
|
28
27
|
attr_accessor :font_scale
|
@@ -153,7 +152,7 @@ module Asciidoctor
|
|
153
152
|
log :warn, %(missing convert handler for #{name} node in #{@backend} backend)
|
154
153
|
end
|
155
154
|
# NOTE: inline node handlers generate HTML-like strings; all other handlers write directly to the PDF object
|
156
|
-
|
155
|
+
node.inline? ? result : self
|
157
156
|
end
|
158
157
|
|
159
158
|
def convert_document doc
|
@@ -339,7 +338,11 @@ module Asciidoctor
|
|
339
338
|
#@page_opts = { size: pdf_opts[:page_size], layout: pdf_opts[:page_layout] }
|
340
339
|
((::Prawn::Document.instance_method :initialize).bind self).call pdf_opts
|
341
340
|
renderer.min_version (@pdf_version = PDFVersions[doc.attr 'pdf-version'])
|
342
|
-
@
|
341
|
+
@tmp_files ||= {}
|
342
|
+
@allow_uri_read = doc.attr? 'allow-uri-read'
|
343
|
+
@cache_uri = doc.attr? 'cache-uri'
|
344
|
+
@jail_dir = doc.safe < ::Asciidoctor::SafeMode::SAFE ? nil : doc.base_dir
|
345
|
+
@media ||= doc.attr 'media', 'screen'
|
343
346
|
@page_margin_by_side = { recto: (page_margin_recto = page_margin), verso: (page_margin_verso = page_margin), cover: page_margin }
|
344
347
|
case doc.attr 'pdf-folio-placement', (@media == 'prepress' ? 'physical' : 'virtual')
|
345
348
|
when 'physical'
|
@@ -364,13 +367,6 @@ module Asciidoctor
|
|
364
367
|
else
|
365
368
|
@ppbook = nil
|
366
369
|
end
|
367
|
-
# QUESTION: should ThemeLoader handle registering fonts instead?
|
368
|
-
register_fonts theme.font_catalog, ((doc.attr 'pdf-fontsdir')&.sub '{docdir}', (doc.attr 'docdir')) || 'GEM_FONTS_DIR'
|
369
|
-
default_kerning theme.base_font_kerning != 'none'
|
370
|
-
@fallback_fonts = Array theme.font_fallbacks
|
371
|
-
@allow_uri_read = doc.attr? 'allow-uri-read'
|
372
|
-
@cache_uri = doc.attr? 'cache-uri'
|
373
|
-
@tmp_files = {}
|
374
370
|
if (bg_image = resolve_background_image doc, theme, 'page-background-image')&.first
|
375
371
|
@page_bg_image = { verso: bg_image, recto: bg_image }
|
376
372
|
else
|
@@ -383,6 +379,10 @@ module Asciidoctor
|
|
383
379
|
@page_bg_image[:recto] = bg_image[0] && bg_image
|
384
380
|
end
|
385
381
|
@page_bg_color = resolve_theme_color :page_background_color, 'FFFFFF'
|
382
|
+
# QUESTION: should ThemeLoader handle registering fonts instead?
|
383
|
+
register_fonts theme.font_catalog, ((doc.attr 'pdf-fontsdir')&.sub '{docdir}', (doc.attr 'docdir')) || 'GEM_FONTS_DIR'
|
384
|
+
default_kerning theme.base_font_kerning != 'none'
|
385
|
+
@fallback_fonts = Array theme.font_fallbacks
|
386
386
|
@root_font_size = theme.base_font_size
|
387
387
|
@font_scale = 1
|
388
388
|
@font_color = theme.base_font_color
|
@@ -939,7 +939,7 @@ module Asciidoctor
|
|
939
939
|
height: label_height,
|
940
940
|
fallback_font_name: fallback_svg_font_name,
|
941
941
|
enable_web_requests: allow_uri_read ? (method :load_open_uri).to_proc : false,
|
942
|
-
enable_file_requests_with_root: (::File.dirname icon_path),
|
942
|
+
enable_file_requests_with_root: { base: (::File.dirname icon_path), root: @jail_dir },
|
943
943
|
cache_images: cache_uri
|
944
944
|
svg_obj.resize height: label_height if svg_obj.document.sizing.output_height > label_height
|
945
945
|
svg_obj.draw
|
@@ -1167,8 +1167,26 @@ module Asciidoctor
|
|
1167
1167
|
alias convert_literal convert_code
|
1168
1168
|
alias convert_listing_or_literal convert_code
|
1169
1169
|
|
1170
|
+
def convert_collapsible node
|
1171
|
+
id = node.id
|
1172
|
+
title = (collapsible_marker = %(\u25bc )) + (node.title? ? node.title : 'Details')
|
1173
|
+
indent_by = theme_font(:caption) { rendered_width_of_string collapsible_marker }
|
1174
|
+
if !at_page_top? && (id || (node.option? 'unbreakable'))
|
1175
|
+
arrange_block node do
|
1176
|
+
add_dest_for_block node if id
|
1177
|
+
tare_first_page_content_stream { ink_caption title }
|
1178
|
+
indent(indent_by) { traverse node }
|
1179
|
+
end
|
1180
|
+
else
|
1181
|
+
add_dest_for_block node if id
|
1182
|
+
tare_first_page_content_stream { ink_caption title }
|
1183
|
+
indent(indent_by) { traverse node }
|
1184
|
+
end
|
1185
|
+
theme_margin :block, :bottom, (next_enclosed_block node)
|
1186
|
+
end
|
1187
|
+
|
1170
1188
|
def convert_example node
|
1171
|
-
return
|
1189
|
+
return convert_collapsible node if node.option? 'collapsible'
|
1172
1190
|
caption_bottom = @theme.example_caption_end&.to_sym == :bottom
|
1173
1191
|
arrange_block node do |extent|
|
1174
1192
|
add_dest_for_block node if node.id
|
@@ -1193,14 +1211,12 @@ module Asciidoctor
|
|
1193
1211
|
if !at_page_top? && (has_title || id || (node.option? 'unbreakable'))
|
1194
1212
|
arrange_block node do
|
1195
1213
|
add_dest_for_block node if id
|
1196
|
-
tare_first_page_content_stream
|
1197
|
-
node.context == :example ? (ink_caption %(\u25bc #{node.title})) : (ink_caption node, labeled: false)
|
1198
|
-
end if has_title
|
1214
|
+
tare_first_page_content_stream { ink_caption node, labeled: false } if has_title
|
1199
1215
|
traverse node
|
1200
1216
|
end
|
1201
1217
|
else
|
1202
1218
|
add_dest_for_block node if id
|
1203
|
-
|
1219
|
+
ink_caption node, labeled: false if has_title
|
1204
1220
|
traverse node
|
1205
1221
|
end
|
1206
1222
|
end
|
@@ -1718,7 +1734,7 @@ module Asciidoctor
|
|
1718
1734
|
file_request_root = false
|
1719
1735
|
else
|
1720
1736
|
svg_data = ::File.read image_path, mode: 'r:UTF-8'
|
1721
|
-
file_request_root = ::File.dirname image_path
|
1737
|
+
file_request_root = { base: (::File.dirname image_path), root: @jail_dir }
|
1722
1738
|
end
|
1723
1739
|
svg_obj = ::Prawn::SVG::Interface.new svg_data, self,
|
1724
1740
|
position: alignment,
|
@@ -1798,7 +1814,7 @@ module Asciidoctor
|
|
1798
1814
|
end
|
1799
1815
|
rescue => e
|
1800
1816
|
raise if ::StopIteration === e
|
1801
|
-
on_image_error :exception, node, target, (opts.merge align: alignment, message: %(could not embed image: #{image_path}; #{e.message}#{
|
1817
|
+
on_image_error :exception, node, target, (opts.merge align: alignment, message: %(could not embed image: #{image_path}; #{e.message}#{(recommend_prawn_gmagick? e, image_format) ? %(; install prawn-gmagick gem to add support for #{image_format&.upcase || 'unknown'} image format) : ''}))
|
1802
1818
|
end
|
1803
1819
|
end
|
1804
1820
|
|
@@ -2492,14 +2508,19 @@ module Asciidoctor
|
|
2492
2508
|
# NOTE: an image with a data URI is handled using a temporary file
|
2493
2509
|
elsif (image_path = resolve_image_path node, target, image_format)
|
2494
2510
|
if ::File.readable? image_path
|
2511
|
+
class_attr = (role = node.role) ? %( class="#{role}") : ''
|
2512
|
+
fit_attr = (fit = node.attr 'fit') ? %( fit="#{fit}") : ''
|
2495
2513
|
if (width = resolve_explicit_width node.attributes)
|
2496
|
-
|
2514
|
+
if node.parent.context == :table_cell && ::String === width && (width.end_with? '%')
|
2515
|
+
width += (intrinsic_image_dimensions image_path, image_format)[:width].to_s
|
2516
|
+
end
|
2517
|
+
width_attr = %( width="#{width}")
|
2518
|
+
elsif state # check that converter is initialized
|
2519
|
+
width_attr = %( width="#{(intrinsic_image_dimensions image_path, image_format)[:width]}")
|
2497
2520
|
else
|
2498
|
-
|
2521
|
+
width_attr = ' width="auto"' # defer operation until arranger runs
|
2499
2522
|
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}>)
|
2523
|
+
img = %(<img src="#{image_path}" format="#{image_format}" alt="#{encode_quotes node.attr 'alt'}"#{width_attr}#{class_attr}#{fit_attr}>)
|
2503
2524
|
else
|
2504
2525
|
log :warn, %(image to embed not found or not readable: #{image_path})
|
2505
2526
|
img = %([#{node.attr 'alt'}])
|
@@ -3001,7 +3022,7 @@ module Asciidoctor
|
|
3001
3022
|
end
|
3002
3023
|
end
|
3003
3024
|
end
|
3004
|
-
theme_font_cascade [
|
3025
|
+
theme_font_cascade ['caption', category_caption] do
|
3005
3026
|
if ((opts.delete :end) || (opts.delete :side) || :top) == :top
|
3006
3027
|
margin = { top: caption_margin_outside, bottom: caption_margin_inside }
|
3007
3028
|
else
|
@@ -3758,7 +3779,6 @@ module Asciidoctor
|
|
3758
3779
|
next if (num_levels_for_entry = (entry.attr 'toclevels', num_levels).to_i) < (entry_level = entry.level + 1).pred ||
|
3759
3780
|
((entry.option? 'notitle') && entry == entry.document.last_child && entry.empty?)
|
3760
3781
|
theme_font :toc, level: entry_level do
|
3761
|
-
next unless (entry_anchor = (entry.attr 'pdf-anchor') || entry.id)
|
3762
3782
|
entry_title = entry.context == :section ? entry.numbered_title : (entry.title? ? entry.title : (entry.xreftext 'basic'))
|
3763
3783
|
next if entry_title.empty?
|
3764
3784
|
entry_title = transform_text entry_title, @text_transform if @text_transform
|
@@ -3770,6 +3790,7 @@ module Asciidoctor
|
|
3770
3790
|
ink_prose entry_title, anchor: true, normalize: false, hanging_indent: hanging_indent, normalize_line_height: true, margin: 0
|
3771
3791
|
end
|
3772
3792
|
else
|
3793
|
+
entry_anchor = (entry.attr 'pdf-anchor') || entry.id
|
3773
3794
|
if !(physical_pgnum = entry.attr 'pdf-page-start') &&
|
3774
3795
|
(target_page_ref = (get_dest entry_anchor)&.first) &&
|
3775
3796
|
(target_page_idx = state.pages.index {|candidate| candidate.dictionary == target_page_ref })
|
@@ -3825,6 +3846,27 @@ module Asciidoctor
|
|
3825
3846
|
end
|
3826
3847
|
end
|
3827
3848
|
|
3849
|
+
# Retrieve the intrinsic image dimensions for the specified path in pt.
|
3850
|
+
#
|
3851
|
+
# Returns a Hash containing :width and :height keys that map to the image's
|
3852
|
+
# intrinsic width and height values (in pt).
|
3853
|
+
def intrinsic_image_dimensions path, format
|
3854
|
+
if format == 'svg'
|
3855
|
+
# NOTE: prawn-svg automatically converts intrinsic width and height to pt
|
3856
|
+
img_obj = ::Prawn::SVG::Interface.new (::File.read path, mode: 'r:UTF-8'), self, {}
|
3857
|
+
img_size = img_obj.document.sizing
|
3858
|
+
{ width: img_size.output_width, height: img_size.output_height }
|
3859
|
+
else
|
3860
|
+
# NOTE: build_image_object caches image data previously loaded
|
3861
|
+
# NOTE: build_image_object computes intrinsic width and height in px
|
3862
|
+
_, img_size = ::File.open(path, 'rb') {|fd| build_image_object fd }
|
3863
|
+
{ width: (to_pt img_size.width, :px), height: (to_pt img_size.height, :px) }
|
3864
|
+
end
|
3865
|
+
rescue
|
3866
|
+
# NOTE: image can't be read, so it won't be used anyway
|
3867
|
+
{ width: 0, height: 0 }
|
3868
|
+
end
|
3869
|
+
|
3828
3870
|
# Sends the specified message to the log unless this method is called from the scratch document
|
3829
3871
|
def log severity, message = nil, &block
|
3830
3872
|
logger.send severity, message, &block unless scratch?
|
@@ -4033,7 +4075,7 @@ module Asciidoctor
|
|
4033
4075
|
def resolve_image_options image_path, image_format, image_attrs, opts = {}
|
4034
4076
|
if image_format == 'svg'
|
4035
4077
|
image_opts = {
|
4036
|
-
enable_file_requests_with_root: (::File.dirname image_path),
|
4078
|
+
enable_file_requests_with_root: { base: (::File.dirname image_path), root: @jail_dir },
|
4037
4079
|
enable_web_requests: allow_uri_read ? (method :load_open_uri).to_proc : false,
|
4038
4080
|
cache_images: cache_uri,
|
4039
4081
|
fallback_font_name: fallback_svg_font_name,
|
@@ -4120,6 +4162,7 @@ module Asciidoctor
|
|
4120
4162
|
else
|
4121
4163
|
imagesdir = relative_to
|
4122
4164
|
end
|
4165
|
+
@tmp_files ||= {}
|
4123
4166
|
# NOTE: base64 logic currently used for inline images
|
4124
4167
|
if ::Base64 === image_path
|
4125
4168
|
return @tmp_files[image_path] if @tmp_files.key? image_path
|
@@ -4346,7 +4389,7 @@ module Asciidoctor
|
|
4346
4389
|
end
|
4347
4390
|
|
4348
4391
|
def theme_font_cascade categories, &block
|
4349
|
-
if ::Array === (category = (categories = categories.
|
4392
|
+
if ::Array === (category = (categories = categories.uniq).shift)
|
4350
4393
|
category, opts = category
|
4351
4394
|
else
|
4352
4395
|
opts = {}
|
@@ -257,10 +257,10 @@ module Asciidoctor
|
|
257
257
|
# Prevents at_page_top? from returning true while yielding to the specified block.
|
258
258
|
#
|
259
259
|
def conceal_page_top
|
260
|
-
margin_box.instance_variable_set :@y, (old_top = margin_box.absolute_top) + 0.0001
|
260
|
+
@margin_box.instance_variable_set :@y, (old_top = @margin_box.absolute_top) + 0.0001
|
261
261
|
yield
|
262
262
|
ensure
|
263
|
-
margin_box.instance_variable_set :@y, old_top
|
263
|
+
@margin_box.instance_variable_set :@y, old_top
|
264
264
|
end
|
265
265
|
|
266
266
|
# Returns whether the current page is the last page in the document.
|
@@ -5,8 +5,12 @@ Prawn::Text::Formatted::Fragment.prepend (Module.new do
|
|
5
5
|
|
6
6
|
# Prevent fragment from being written by discarding the text, optionally forcing the width to 0
|
7
7
|
def conceal force_width_to_zero = false
|
8
|
-
|
9
|
-
|
8
|
+
if force_width_to_zero
|
9
|
+
@width = 0
|
10
|
+
@text = ''
|
11
|
+
else
|
12
|
+
@text = ' ' * space_count # preserve space_count so width is still computed correctly
|
13
|
+
end
|
10
14
|
end
|
11
15
|
|
12
16
|
# Don't strip soft hyphens when repacking unretrieved fragments
|
@@ -33,25 +33,8 @@ module Asciidoctor
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
|
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
|
@@ -9,11 +9,16 @@ module Asciidoctor::PDF::FormattedText
|
|
9
9
|
text = fragment.text
|
10
10
|
x = fragment.left
|
11
11
|
y = fragment.baseline
|
12
|
-
align = fragment.format_state[:align]
|
13
|
-
if
|
14
|
-
|
12
|
+
align = (format_state = fragment.format_state)[:align]
|
13
|
+
if align == :center || align == :right
|
14
|
+
gap_width = (format_state.key? :width) ?
|
15
|
+
fragment.width - (document.width_of text) :
|
16
|
+
(format_state[:border_offset] || 0) * 2
|
17
|
+
x += gap_width * (align == :center ? 0.5 : 1) if gap_width > 0
|
18
|
+
end
|
19
|
+
document.word_spacing fragment.word_spacing do
|
20
|
+
document.draw_text! text, at: [x, y], kerning: document.default_kerning?
|
15
21
|
end
|
16
|
-
document.draw_text! text, at: [x, y]
|
17
22
|
fragment.conceal
|
18
23
|
end
|
19
24
|
end
|
@@ -36,8 +36,7 @@ module Asciidoctor::PDF::FormattedText
|
|
36
36
|
end
|
37
37
|
pdf.fill_color prev_fill_color
|
38
38
|
end
|
39
|
-
if (border_width = data[:border_width])
|
40
|
-
border_color = data[:border_color]
|
39
|
+
if (border_width = data[:border_width]) && (border_color = data[:border_color])
|
41
40
|
prev_stroke_color = pdf.stroke_color
|
42
41
|
prev_line_width = pdf.line_width
|
43
42
|
pdf.stroke_color border_color
|
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.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-
|
12
|
+
date: 2022-06-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: asciidoctor
|
@@ -258,8 +258,12 @@ files:
|
|
258
258
|
- lib/asciidoctor/pdf/ext/core/string.rb
|
259
259
|
- lib/asciidoctor/pdf/ext/pdf-core.rb
|
260
260
|
- lib/asciidoctor/pdf/ext/pdf-core/page.rb
|
261
|
+
- lib/asciidoctor/pdf/ext/prawn-gmagick.rb
|
261
262
|
- lib/asciidoctor/pdf/ext/prawn-svg.rb
|
263
|
+
- lib/asciidoctor/pdf/ext/prawn-svg/calculators/document_sizing.rb
|
264
|
+
- lib/asciidoctor/pdf/ext/prawn-svg/elements/image.rb
|
262
265
|
- lib/asciidoctor/pdf/ext/prawn-svg/loaders/data.rb
|
266
|
+
- lib/asciidoctor/pdf/ext/prawn-svg/loaders/file.rb
|
263
267
|
- lib/asciidoctor/pdf/ext/prawn-svg/loaders/web.rb
|
264
268
|
- lib/asciidoctor/pdf/ext/prawn-svg/url_loader.rb
|
265
269
|
- lib/asciidoctor/pdf/ext/prawn-table.rb
|