asciidoctor-pdf 1.5.0.beta.8 → 1.5.0.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +49 -0
- data/LICENSE.adoc +1 -1
- data/NOTICE.adoc +1 -1
- data/README.adoc +43 -47
- data/asciidoctor-pdf.gemspec +5 -1
- data/bin/asciidoctor-pdf-optimize +1 -1
- data/data/themes/base-theme.yml +4 -3
- data/data/themes/default-theme.yml +10 -5
- data/docs/theming-guide.adoc +286 -22
- data/lib/asciidoctor-pdf.rb +1 -0
- data/lib/asciidoctor-pdf/converter.rb +1 -0
- data/lib/asciidoctor-pdf/version.rb +1 -0
- data/lib/asciidoctor/pdf.rb +13 -2
- data/lib/asciidoctor/pdf/converter.rb +3962 -3955
- data/lib/asciidoctor/pdf/ext.rb +9 -0
- data/lib/asciidoctor/pdf/ext/asciidoctor.rb +1 -0
- data/lib/asciidoctor/pdf/ext/asciidoctor/abstract_block.rb +1 -0
- data/lib/asciidoctor/pdf/ext/asciidoctor/abstract_node.rb +1 -0
- data/lib/asciidoctor/pdf/ext/asciidoctor/document.rb +1 -0
- data/lib/asciidoctor/pdf/ext/asciidoctor/image.rb +18 -16
- data/lib/asciidoctor/pdf/ext/asciidoctor/list.rb +3 -2
- data/lib/asciidoctor/pdf/ext/asciidoctor/list_item.rb +2 -1
- data/lib/asciidoctor/pdf/ext/asciidoctor/logging_shim.rb +3 -4
- data/lib/asciidoctor/pdf/ext/asciidoctor/section.rb +8 -6
- data/lib/asciidoctor/pdf/ext/core.rb +2 -0
- data/lib/asciidoctor/pdf/ext/core/array.rb +1 -0
- data/lib/asciidoctor/pdf/ext/core/hash.rb +1 -0
- data/lib/asciidoctor/pdf/ext/core/numeric.rb +4 -3
- data/lib/asciidoctor/pdf/ext/core/object.rb +1 -0
- data/lib/asciidoctor/pdf/ext/core/quantifiable_stdout.rb +8 -1
- data/lib/asciidoctor/pdf/ext/core/regexp.rb +1 -0
- data/lib/asciidoctor/pdf/ext/core/string.rb +6 -7
- data/lib/asciidoctor/pdf/ext/pdf-core.rb +1 -0
- data/lib/asciidoctor/pdf/ext/pdf-core/page.rb +3 -4
- data/lib/asciidoctor/pdf/ext/pdf-core/pdf_object.rb +2 -1
- data/lib/asciidoctor/pdf/ext/prawn-svg.rb +1 -0
- data/lib/asciidoctor/pdf/ext/prawn-svg/interface.rb +11 -8
- data/lib/asciidoctor/pdf/ext/prawn-table.rb +2 -1
- data/lib/asciidoctor/pdf/ext/prawn-table/cell.rb +9 -10
- data/lib/asciidoctor/pdf/ext/prawn-table/cell/asciidoc.rb +62 -57
- data/lib/asciidoctor/pdf/ext/prawn-table/cell/text.rb +5 -3
- data/lib/asciidoctor/pdf/ext/prawn-templates.rb +1 -0
- data/lib/asciidoctor/pdf/ext/prawn.rb +1 -0
- data/lib/asciidoctor/pdf/ext/prawn/coderay_encoder.rb +73 -72
- data/lib/asciidoctor/pdf/ext/prawn/extensions.rb +814 -818
- data/lib/asciidoctor/pdf/ext/prawn/font/afm.rb +4 -3
- data/lib/asciidoctor/pdf/ext/prawn/formatted_text/box.rb +2 -1
- data/lib/asciidoctor/pdf/ext/prawn/formatted_text/fragment.rb +7 -2
- data/lib/asciidoctor/pdf/ext/prawn/images.rb +45 -44
- data/lib/asciidoctor/pdf/ext/pygments.rb +34 -0
- data/lib/asciidoctor/pdf/ext/rouge.rb +1 -1
- data/lib/asciidoctor/pdf/ext/rouge/formatters/prawn.rb +181 -149
- data/lib/asciidoctor/pdf/ext/rouge/themes/asciidoctor_pdf_default.rb +1 -0
- data/lib/asciidoctor/pdf/formatted_text.rb +2 -0
- data/lib/asciidoctor/pdf/formatted_text/formatter.rb +35 -34
- data/lib/asciidoctor/pdf/formatted_text/fragment_position_renderer.rb +8 -7
- data/lib/asciidoctor/pdf/formatted_text/inline_destination_marker.rb +13 -14
- data/lib/asciidoctor/pdf/formatted_text/inline_image_arranger.rb +112 -133
- data/lib/asciidoctor/pdf/formatted_text/inline_image_renderer.rb +43 -41
- data/lib/asciidoctor/pdf/formatted_text/inline_text_aligner.rb +15 -14
- data/lib/asciidoctor/pdf/formatted_text/source_wrap.rb +43 -0
- data/lib/asciidoctor/pdf/formatted_text/text_background_and_border_renderer.rb +46 -37
- data/lib/asciidoctor/pdf/formatted_text/transform.rb +371 -352
- data/lib/asciidoctor/pdf/index_catalog.rb +99 -95
- data/lib/asciidoctor/pdf/measurements.rb +51 -48
- data/lib/asciidoctor/pdf/optimizer.rb +34 -31
- data/lib/asciidoctor/pdf/pdfmark.rb +34 -33
- data/lib/asciidoctor/pdf/roman_numeral.rb +80 -79
- data/lib/asciidoctor/pdf/sanitizer.rb +38 -37
- data/lib/asciidoctor/pdf/temporary_path.rb +10 -9
- data/lib/asciidoctor/pdf/text_transformer.rb +101 -100
- data/lib/asciidoctor/pdf/theme_loader.rb +258 -256
- data/lib/asciidoctor/pdf/version.rb +5 -4
- metadata +55 -6
- data/lib/asciidoctor/pdf/ext/rouge/themes/bw.rb +0 -39
- data/lib/asciidoctor/pdf/ext/ttfunk.rb +0 -9
@@ -1,129 +1,133 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
module Asciidoctor; module PDF
|
3
|
-
class IndexCatalog
|
4
|
-
include ::Asciidoctor::PDF::TextTransformer
|
5
2
|
|
6
|
-
|
3
|
+
module Asciidoctor
|
4
|
+
module PDF
|
5
|
+
class IndexCatalog
|
6
|
+
include ::Asciidoctor::PDF::TextTransformer
|
7
7
|
|
8
|
-
|
8
|
+
LeadingAlphaRx = /^\p{Alpha}/
|
9
9
|
|
10
|
-
|
11
|
-
@categories = {}
|
12
|
-
@start_page_number = 1
|
13
|
-
@dests = {}
|
14
|
-
@sequence = 0
|
15
|
-
end
|
10
|
+
attr_accessor :start_page_number
|
16
11
|
|
17
|
-
|
18
|
-
|
19
|
-
|
12
|
+
def initialize
|
13
|
+
@categories = {}
|
14
|
+
@start_page_number = 1
|
15
|
+
@dests = {}
|
16
|
+
@sequence = 0
|
17
|
+
end
|
20
18
|
|
21
|
-
|
22
|
-
|
23
|
-
store_tertiary_term names[0], names[1], names[2], dest
|
24
|
-
elsif num_terms == 2
|
25
|
-
store_secondary_term names[0], names[1], dest
|
26
|
-
elsif num_terms == 1
|
27
|
-
store_primary_term names[0], dest
|
19
|
+
def next_anchor_name
|
20
|
+
%(__indexterm-#{@sequence += 1})
|
28
21
|
end
|
29
|
-
end
|
30
22
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
23
|
+
def store_term names, dest = nil
|
24
|
+
if (num_terms = names.size) > 2
|
25
|
+
store_tertiary_term names[0], names[1], names[2], dest
|
26
|
+
elsif num_terms == 2
|
27
|
+
store_secondary_term names[0], names[1], dest
|
28
|
+
elsif num_terms == 1
|
29
|
+
store_primary_term names[0], dest
|
30
|
+
end
|
31
|
+
end
|
35
32
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
33
|
+
def store_primary_term name, dest = nil
|
34
|
+
store_dest dest if dest
|
35
|
+
(init_category uppercase_mb name.chr).store_term name, dest
|
36
|
+
end
|
40
37
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
38
|
+
def store_secondary_term primary_name, secondary_name, dest = nil
|
39
|
+
store_dest dest if dest
|
40
|
+
(store_primary_term primary_name).store_term secondary_name, dest
|
41
|
+
end
|
45
42
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
43
|
+
def store_tertiary_term primary_name, secondary_name, tertiary_name, dest = nil
|
44
|
+
store_dest dest if dest
|
45
|
+
(store_secondary_term primary_name, secondary_name).store_term tertiary_name, dest
|
46
|
+
end
|
50
47
|
|
51
|
-
|
52
|
-
|
53
|
-
|
48
|
+
def init_category name
|
49
|
+
name = '@' unless LeadingAlphaRx.match? name
|
50
|
+
@categories[name] ||= IndexTermCategory.new name
|
51
|
+
end
|
54
52
|
|
55
|
-
|
56
|
-
|
57
|
-
|
53
|
+
def find_category name
|
54
|
+
@categories[name]
|
55
|
+
end
|
58
56
|
|
59
|
-
|
60
|
-
|
61
|
-
dest[:page] = physical_page_number - (@start_page_number - 1)
|
57
|
+
def store_dest dest
|
58
|
+
@dests[dest[:anchor]] = dest
|
62
59
|
end
|
63
|
-
end
|
64
60
|
|
65
|
-
|
66
|
-
|
67
|
-
|
61
|
+
def link_dest_to_page anchor, physical_page_number
|
62
|
+
if (dest = @dests[anchor])
|
63
|
+
virtual_page_number = physical_page_number - (@start_page_number - 1)
|
64
|
+
dest[:page] = (virtual_page_number < 1 ? (RomanNumeral.new physical_page_number, :lower) : virtual_page_number).to_s
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def empty?
|
69
|
+
@categories.empty?
|
70
|
+
end
|
68
71
|
|
69
|
-
|
70
|
-
|
72
|
+
def categories
|
73
|
+
@categories.empty? ? [] : @categories.values.sort
|
74
|
+
end
|
71
75
|
end
|
72
|
-
end
|
73
76
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
+
class IndexTermGroup
|
78
|
+
include Comparable
|
79
|
+
attr_reader :name
|
77
80
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
81
|
+
def initialize name
|
82
|
+
@name = name
|
83
|
+
@terms = {}
|
84
|
+
end
|
82
85
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
86
|
+
def store_term name, dest = nil
|
87
|
+
term = (@terms[name] ||= (IndexTerm.new name))
|
88
|
+
term.add_dest dest if dest
|
89
|
+
term
|
90
|
+
end
|
88
91
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
+
def find_term name
|
93
|
+
@terms[name]
|
94
|
+
end
|
92
95
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
+
def terms
|
97
|
+
@terms.empty? ? [] : @terms.values.sort
|
98
|
+
end
|
96
99
|
|
97
|
-
|
98
|
-
|
100
|
+
def <=> other
|
101
|
+
(val = @name.casecmp other.name) == 0 ? @name <=> other.name : val
|
102
|
+
end
|
99
103
|
end
|
100
|
-
end
|
101
104
|
|
102
|
-
|
105
|
+
class IndexTermCategory < IndexTermGroup; end
|
103
106
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
107
|
+
class IndexTerm < IndexTermGroup
|
108
|
+
def initialize name
|
109
|
+
super
|
110
|
+
@dests = ::Set.new
|
111
|
+
end
|
109
112
|
|
110
|
-
|
113
|
+
alias subterms terms
|
111
114
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
115
|
+
def add_dest dest
|
116
|
+
@dests << dest
|
117
|
+
self
|
118
|
+
end
|
116
119
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
+
def dests
|
121
|
+
@dests.select {|d| d.key? :page }.sort {|a, b| a[:page] <=> b[:page] }
|
122
|
+
end
|
120
123
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
+
def container?
|
125
|
+
@dests.empty? || @dests.none? {|d| d.key? :page }
|
126
|
+
end
|
124
127
|
|
125
|
-
|
126
|
-
|
128
|
+
def leaf?
|
129
|
+
@terms.empty?
|
130
|
+
end
|
127
131
|
end
|
128
132
|
end
|
129
|
-
end
|
133
|
+
end
|
@@ -1,59 +1,62 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
module Asciidoctor; module PDF
|
3
|
-
module Measurements
|
4
|
-
MeasurementValueRx = /(\d+|\d*\.\d+)(in|mm|cm|p[txc])?$/
|
5
|
-
InsetMeasurementValueRx = /(?<=^| |\()(-?\d+(?:\.\d+)?)(in|mm|cm|p[txc])(?=$| |\))/
|
6
|
-
MeasurementValueHintRx = /\d(in|mm|cm|p[txc])/
|
7
2
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
3
|
+
module Asciidoctor
|
4
|
+
module PDF
|
5
|
+
module Measurements
|
6
|
+
MeasurementValueRx = /(\d+|\d*\.\d+)(in|mm|cm|p[txc])?$/
|
7
|
+
InsetMeasurementValueRx = /(?<=^| |\()(-?\d+(?:\.\d+)?)(in|mm|cm|p[txc])(?=$| |\))/
|
8
|
+
MeasurementValueHintRx = /\d(in|mm|cm|p[txc])/
|
9
|
+
|
10
|
+
# Convert the specified string value to a pt value from the
|
11
|
+
# specified unit of measurement (e.g., in, cm, mm, etc).
|
12
|
+
# If the unit of measurement is not recognized, assume pt.
|
13
|
+
#
|
14
|
+
# Examples:
|
15
|
+
#
|
16
|
+
# 0.5in => 36.0
|
17
|
+
# 100px => 75.0
|
18
|
+
# 72blah => 72.0
|
19
|
+
#
|
20
|
+
def str_to_pt val
|
21
|
+
MeasurementValueRx =~ val ? (to_pt $1.to_f, $2) : val.to_f
|
22
|
+
end
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
num
|
29
|
-
else
|
30
|
-
case units
|
31
|
-
when 'pt'
|
24
|
+
# Converts the specified float value to a pt value from the
|
25
|
+
# specified unit of measurement (e.g., in, cm, mm, etc).
|
26
|
+
# Raises an argument error if the unit of measurement is not recognized.
|
27
|
+
def to_pt num, units
|
28
|
+
units = units.to_s if ::Symbol === units
|
29
|
+
if units.nil_or_empty?
|
32
30
|
num
|
33
|
-
when 'in'
|
34
|
-
num * 72
|
35
|
-
when 'mm'
|
36
|
-
num * (72 / 25.4)
|
37
|
-
when 'cm'
|
38
|
-
num * (720 / 25.4)
|
39
|
-
when 'px'
|
40
|
-
# assuming canvas of 96 dpi
|
41
|
-
num * 0.75
|
42
|
-
when 'pc'
|
43
|
-
num * 12
|
44
31
|
else
|
45
|
-
|
32
|
+
case units
|
33
|
+
when 'pt'
|
34
|
+
num
|
35
|
+
when 'in'
|
36
|
+
num * 72
|
37
|
+
when 'mm'
|
38
|
+
num * (72 / 25.4)
|
39
|
+
when 'cm'
|
40
|
+
num * (720 / 25.4)
|
41
|
+
when 'px'
|
42
|
+
# assuming canvas of 96 dpi
|
43
|
+
num * 0.75
|
44
|
+
when 'pc'
|
45
|
+
num * 12
|
46
|
+
else
|
47
|
+
raise ::ArgumentError, %(unknown unit of measurement: #{units})
|
48
|
+
end
|
46
49
|
end
|
47
50
|
end
|
48
|
-
end
|
49
51
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
52
|
+
# Resolve measurement values in the string to PDF points.
|
53
|
+
def resolve_measurement_values str
|
54
|
+
if MeasurementValueHintRx.match? str
|
55
|
+
str.gsub(InsetMeasurementValueRx) { to_pt $1.to_f, $2 }
|
56
|
+
else
|
57
|
+
str
|
58
|
+
end
|
56
59
|
end
|
57
60
|
end
|
58
61
|
end
|
59
|
-
end
|
62
|
+
end
|
@@ -1,41 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pathname'
|
1
4
|
require 'rghost'
|
2
5
|
require 'tmpdir'
|
3
6
|
|
4
7
|
module Asciidoctor
|
5
|
-
module PDF
|
6
|
-
class Optimizer
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
module PDF
|
9
|
+
class Optimizer
|
10
|
+
(QUALITY_NAMES = {
|
11
|
+
'default' => :default,
|
12
|
+
'screen' => :screen,
|
13
|
+
'ebook' => :ebook,
|
14
|
+
'printer' => :printer,
|
15
|
+
'prepress' => :prepress,
|
16
|
+
}).default = :default
|
14
17
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
18
|
+
def initialize quality = 'default', compatibility_level = '1.4'
|
19
|
+
@quality = QUALITY_NAMES[quality]
|
20
|
+
@compatibility_level = compatibility_level
|
21
|
+
end
|
19
22
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
23
|
+
def generate_file target
|
24
|
+
::Dir::Tmpname.create ['asciidoctor-pdf-', '.pdf'] do |tmpfile|
|
25
|
+
filename = Pathname.new target
|
26
|
+
filename_o = Pathname.new tmpfile
|
27
|
+
pdfmark = filename.sub_ext '.pdfmark'
|
28
|
+
inputs = pdfmark.file? ? [target, pdfmark.to_s] : target
|
29
|
+
(::RGhost::Convert.new inputs).to :pdf,
|
30
|
+
filename: filename_o.to_s,
|
31
|
+
quality: @quality,
|
32
|
+
d: { Printed: false, CannotEmbedFontPolicy: '/Warning', CompatibilityLevel: @compatibility_level }
|
33
|
+
begin
|
34
|
+
filename_o.rename target
|
35
|
+
rescue ::Errno::EXDEV
|
36
|
+
filename.binwrite filename_o.binread
|
37
|
+
filename_o.unlink
|
38
|
+
end
|
39
|
+
end
|
40
|
+
nil
|
35
41
|
end
|
36
42
|
end
|
37
|
-
nil
|
38
43
|
end
|
39
44
|
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,40 +1,41 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Asciidoctor
|
3
|
-
module PDF
|
4
|
-
class Pdfmark
|
5
|
-
|
4
|
+
module PDF
|
5
|
+
class Pdfmark
|
6
|
+
include ::Asciidoctor::PDF::Sanitizer
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
def initialize doc
|
9
|
+
@doc = doc
|
10
|
+
end
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
12
|
+
def generate
|
13
|
+
doc = @doc
|
14
|
+
if doc.attr? 'reproducible'
|
15
|
+
mod_date = creation_date = (::Time.at 0).utc
|
16
|
+
else
|
17
|
+
mod_date = (::Time.parse doc.attr 'docdatetime') rescue (now ||= ::Time.now)
|
18
|
+
creation_date = (::Time.parse doc.attr 'localdatetime') rescue (now || ::Time.now)
|
19
|
+
end
|
20
|
+
# FIXME: use sanitize: :plain_text once available
|
21
|
+
content = <<~EOS
|
22
|
+
[ /Title #{(sanitize doc.doctitle use_fallback: true).to_pdf_object}
|
23
|
+
/Author #{(doc.attr 'authors').to_pdf_object}
|
24
|
+
/Subject #{(doc.attr 'subject').to_pdf_object}
|
25
|
+
/Keywords #{(doc.attr 'keywords').to_pdf_object}
|
26
|
+
/ModDate #{mod_date.to_pdf_object}
|
27
|
+
/CreationDate #{creation_date.to_pdf_object}
|
28
|
+
/Creator (Asciidoctor PDF #{::Asciidoctor::PDF::VERSION}, based on Prawn #{::Prawn::VERSION})
|
29
|
+
/Producer #{(doc.attr 'publisher').to_pdf_object}
|
30
|
+
/DOCINFO pdfmark
|
31
|
+
EOS
|
32
|
+
content
|
33
|
+
end
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
def generate_file pdf_file
|
36
|
+
# QUESTION should we use the extension pdfmeta to be more clear?
|
37
|
+
::File.write %(#{pdf_file}mark), generate
|
38
|
+
end
|
39
|
+
end
|
37
40
|
end
|
38
41
|
end
|
39
|
-
end
|
40
|
-
end
|