pdf-core 0.4.0 → 0.10.0
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 +5 -5
- checksums.yaml.gz.sig +0 -0
- data/lib/pdf/core/annotations.rb +58 -21
- data/lib/pdf/core/byte_string.rb +6 -3
- data/lib/pdf/core/destinations.rb +77 -34
- data/lib/pdf/core/document_state.rb +121 -30
- data/lib/pdf/core/filter_list.rb +47 -6
- data/lib/pdf/core/filters.rb +31 -12
- data/lib/pdf/core/graphics_state.rb +80 -32
- data/lib/pdf/core/literal_string.rb +11 -10
- data/lib/pdf/core/name_tree.rb +118 -54
- data/lib/pdf/core/object_store.rb +82 -37
- data/lib/pdf/core/outline_item.rb +62 -7
- data/lib/pdf/core/outline_root.rb +21 -3
- data/lib/pdf/core/page.rb +232 -77
- data/lib/pdf/core/page_geometry.rb +56 -112
- data/lib/pdf/core/pdf_object.rb +93 -57
- data/lib/pdf/core/reference.rb +70 -30
- data/lib/pdf/core/renderer.rb +149 -68
- data/lib/pdf/core/stream.rb +48 -12
- data/lib/pdf/core/text.rb +300 -106
- data/lib/pdf/core/utils.rb +21 -0
- data/lib/pdf/core.rb +38 -25
- data/pdf-core.gemspec +43 -24
- data.tar.gz.sig +0 -0
- metadata +56 -64
- metadata.gz.sig +2 -0
- data/Gemfile +0 -3
- data/Rakefile +0 -11
- data/spec/filters_spec.rb +0 -34
- data/spec/name_tree_spec.rb +0 -122
- data/spec/object_store_spec.rb +0 -49
- data/spec/pdf_object_spec.rb +0 -172
- data/spec/reference_spec.rb +0 -62
- data/spec/spec_helper.rb +0 -32
- data/spec/stream_spec.rb +0 -59
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Describes PDF page geometries
|
|
4
4
|
#
|
|
@@ -8,119 +8,63 @@
|
|
|
8
8
|
|
|
9
9
|
module PDF
|
|
10
10
|
module Core
|
|
11
|
-
|
|
12
11
|
# Dimensions pulled from PDF::Writer, rubyforge.org/projects/ruby-pdf
|
|
13
|
-
#
|
|
14
|
-
# All of these dimensions are in PDF Points (1/72 inch)
|
|
15
|
-
#
|
|
16
|
-
# ===Inbuilt Sizes:
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
# 4A0:: => 4767.87 x 6740.79
|
|
20
|
-
# 2A0:: => 3370.39 x 4767.87
|
|
21
|
-
# A0:: => 2383.94 x 3370.39
|
|
22
|
-
# A1:: => 1683.78 x 2383.94
|
|
23
|
-
# A2:: => 1190.55 x 1683.78
|
|
24
|
-
# A3:: => 841.89 x 1190.55
|
|
25
|
-
# A4:: => 595.28 x 841.89
|
|
26
|
-
# A5:: => 419.53 x 595.28
|
|
27
|
-
# A6:: => 297.64 x 419.53
|
|
28
|
-
# A7:: => 209.76 x 297.64
|
|
29
|
-
# A8:: => 147.40 x 209.76
|
|
30
|
-
# A9:: => 104.88 x 147.40
|
|
31
|
-
# A10:: => 73.70 x 104.88
|
|
32
|
-
# B0:: => 2834.65 x 4008.19
|
|
33
|
-
# B1:: => 2004.09 x 2834.65
|
|
34
|
-
# B2:: => 1417.32 x 2004.09
|
|
35
|
-
# B3:: => 1000.63 x 1417.32
|
|
36
|
-
# B4:: => 708.66 x 1000.63
|
|
37
|
-
# B5:: => 498.90 x 708.66
|
|
38
|
-
# B6:: => 354.33 x 498.90
|
|
39
|
-
# B7:: => 249.45 x 354.33
|
|
40
|
-
# B8:: => 175.75 x 249.45
|
|
41
|
-
# B9:: => 124.72 x 175.75
|
|
42
|
-
# B10:: => 87.87 x 124.72
|
|
43
|
-
# C0:: => 2599.37 x 3676.54
|
|
44
|
-
# C1:: => 1836.85 x 2599.37
|
|
45
|
-
# C2:: => 1298.27 x 1836.85
|
|
46
|
-
# C3:: => 918.43 x 1298.27
|
|
47
|
-
# C4:: => 649.13 x 918.43
|
|
48
|
-
# C5:: => 459.21 x 649.13
|
|
49
|
-
# C6:: => 323.15 x 459.21
|
|
50
|
-
# C7:: => 229.61 x 323.15
|
|
51
|
-
# C8:: => 161.57 x 229.61
|
|
52
|
-
# C9:: => 113.39 x 161.57
|
|
53
|
-
# C10:: => 79.37 x 113.39
|
|
54
|
-
# RA0:: => 2437.80 x 3458.27
|
|
55
|
-
# RA1:: => 1729.13 x 2437.80
|
|
56
|
-
# RA2:: => 1218.90 x 1729.13
|
|
57
|
-
# RA3:: => 864.57 x 1218.90
|
|
58
|
-
# RA4:: => 609.45 x 864.57
|
|
59
|
-
# SRA0:: => 2551.18 x 3628.35
|
|
60
|
-
# SRA1:: => 1814.17 x 2551.18
|
|
61
|
-
# SRA2:: => 1275.59 x 1814.17
|
|
62
|
-
# SRA3:: => 907.09 x 1275.59
|
|
63
|
-
# SRA4:: => 637.80 x 907.09
|
|
64
|
-
# EXECUTIVE:: => 521.86 x 756.00
|
|
65
|
-
# FOLIO:: => 612.00 x 936.00
|
|
66
|
-
# LEGAL:: => 612.00 x 1008.00
|
|
67
|
-
# LETTER:: => 612.00 x 792.00
|
|
68
|
-
# TABLOID:: => 792.00 x 1224.00
|
|
69
|
-
#
|
|
70
12
|
module PageGeometry
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
13
|
+
# Named page sizes.
|
|
14
|
+
#
|
|
15
|
+
# All of these dimensions are in PDF Points (1/72 inch).
|
|
16
|
+
SIZES = {
|
|
17
|
+
'4A0' => [4767.87, 6740.79],
|
|
18
|
+
'2A0' => [3370.39, 4767.87],
|
|
19
|
+
'A0' => [2383.94, 3370.39],
|
|
20
|
+
'A1' => [1683.78, 2383.94],
|
|
21
|
+
'A2' => [1190.55, 1683.78],
|
|
22
|
+
'A3' => [841.89, 1190.55],
|
|
23
|
+
'A4' => [595.28, 841.89],
|
|
24
|
+
'A5' => [419.53, 595.28],
|
|
25
|
+
'A6' => [297.64, 419.53],
|
|
26
|
+
'A7' => [209.76, 297.64],
|
|
27
|
+
'A8' => [147.40, 209.76],
|
|
28
|
+
'A9' => [104.88, 147.40],
|
|
29
|
+
'A10' => [73.70, 104.88],
|
|
30
|
+
'B0' => [2834.65, 4008.19],
|
|
31
|
+
'B1' => [2004.09, 2834.65],
|
|
32
|
+
'B2' => [1417.32, 2004.09],
|
|
33
|
+
'B3' => [1000.63, 1417.32],
|
|
34
|
+
'B4' => [708.66, 1000.63],
|
|
35
|
+
'B5' => [498.90, 708.66],
|
|
36
|
+
'B6' => [354.33, 498.90],
|
|
37
|
+
'B7' => [249.45, 354.33],
|
|
38
|
+
'B8' => [175.75, 249.45],
|
|
39
|
+
'B9' => [124.72, 175.75],
|
|
40
|
+
'B10' => [87.87, 124.72],
|
|
41
|
+
'C0' => [2599.37, 3676.54],
|
|
42
|
+
'C1' => [1836.85, 2599.37],
|
|
43
|
+
'C2' => [1298.27, 1836.85],
|
|
44
|
+
'C3' => [918.43, 1298.27],
|
|
45
|
+
'C4' => [649.13, 918.43],
|
|
46
|
+
'C5' => [459.21, 649.13],
|
|
47
|
+
'C6' => [323.15, 459.21],
|
|
48
|
+
'C7' => [229.61, 323.15],
|
|
49
|
+
'C8' => [161.57, 229.61],
|
|
50
|
+
'C9' => [113.39, 161.57],
|
|
51
|
+
'C10' => [79.37, 113.39],
|
|
52
|
+
'RA0' => [2437.80, 3458.27],
|
|
53
|
+
'RA1' => [1729.13, 2437.80],
|
|
54
|
+
'RA2' => [1218.90, 1729.13],
|
|
55
|
+
'RA3' => [864.57, 1218.90],
|
|
56
|
+
'RA4' => [609.45, 864.57],
|
|
57
|
+
'SRA0' => [2551.18, 3628.35],
|
|
58
|
+
'SRA1' => [1814.17, 2551.18],
|
|
59
|
+
'SRA2' => [1275.59, 1814.17],
|
|
60
|
+
'SRA3' => [907.09, 1275.59],
|
|
61
|
+
'SRA4' => [637.80, 907.09],
|
|
62
|
+
'EXECUTIVE' => [521.86, 756.00],
|
|
63
|
+
'FOLIO' => [612.00, 936.00],
|
|
64
|
+
'LEGAL' => [612.00, 1008.00],
|
|
65
|
+
'LETTER' => [612.00, 792.00],
|
|
66
|
+
'TABLOID' => [792.00, 1224.00],
|
|
67
|
+
}.freeze
|
|
123
68
|
end
|
|
124
69
|
end
|
|
125
70
|
end
|
|
126
|
-
|
data/lib/pdf/core/pdf_object.rb
CHANGED
|
@@ -1,95 +1,131 @@
|
|
|
1
|
-
#
|
|
2
|
-
#
|
|
3
|
-
# pdf_object.rb : Handles Ruby to PDF object serialization
|
|
4
|
-
#
|
|
5
|
-
# Copyright April 2008, Gregory Brown. All Rights Reserved.
|
|
6
|
-
#
|
|
7
|
-
# This is free software. Please see the LICENSE and COPYING files for details.
|
|
1
|
+
# frozen_string_literal: true
|
|
8
2
|
|
|
9
|
-
# Top level Module
|
|
10
|
-
#
|
|
11
3
|
module PDF
|
|
12
4
|
module Core
|
|
13
5
|
module_function
|
|
14
6
|
|
|
7
|
+
# Serializes floating number into a string
|
|
8
|
+
#
|
|
9
|
+
# @param num [Numeric]
|
|
10
|
+
# @return [String]
|
|
11
|
+
def real(num)
|
|
12
|
+
result = format('%.5f', num)
|
|
13
|
+
result.sub!(/((?<!\.)0)+\z/, '')
|
|
14
|
+
result
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Serializes a n array of numbers. This is specifically for use in PDF
|
|
18
|
+
# content streams.
|
|
19
|
+
#
|
|
20
|
+
# @param array [Array<Numeric>]
|
|
21
|
+
# @return [String]
|
|
22
|
+
def real_params(array)
|
|
23
|
+
array.map { |e| real(e) }.join(' ')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Converts string to UTF-16BE encoding as expected by PDF.
|
|
27
|
+
#
|
|
28
|
+
# @param str [String]
|
|
29
|
+
# @return [String]
|
|
30
|
+
# @api private
|
|
15
31
|
def utf8_to_utf16(str)
|
|
16
|
-
"\xFE\xFF".force_encoding(::Encoding::UTF_16BE)
|
|
32
|
+
(+"\xFE\xFF").force_encoding(::Encoding::UTF_16BE) <<
|
|
33
|
+
str.encode(::Encoding::UTF_16BE)
|
|
17
34
|
end
|
|
18
35
|
|
|
19
|
-
#
|
|
36
|
+
# Encodes any string into a hex representation. The result is a string
|
|
20
37
|
# with only 0-9 and a-f characters. That result is valid ASCII so tag
|
|
21
|
-
# it as such to account for behaviour of different ruby VMs
|
|
38
|
+
# it as such to account for behaviour of different ruby VMs.
|
|
39
|
+
#
|
|
40
|
+
# @param str [String]
|
|
41
|
+
# @return [String]
|
|
22
42
|
def string_to_hex(str)
|
|
23
|
-
str.
|
|
43
|
+
str.unpack1('H*').force_encoding(::Encoding::US_ASCII)
|
|
24
44
|
end
|
|
25
45
|
|
|
46
|
+
# Characters to escape in name objects
|
|
47
|
+
# @api private
|
|
48
|
+
ESCAPED_NAME_CHARACTERS = (1..32).to_a + [35, 40, 41, 47, 60, 62] + (127..255).to_a
|
|
49
|
+
|
|
50
|
+
# How to escape special characters in literal strings
|
|
51
|
+
# @api private
|
|
52
|
+
STRING_ESCAPE_MAP = { '(' => '\(', ')' => '\)', '\\' => '\\\\', "\r" => '\r' }.freeze
|
|
53
|
+
|
|
26
54
|
# Serializes Ruby objects to their PDF equivalents. Most primitive objects
|
|
27
55
|
# will work as expected, but please note that Name objects are represented
|
|
28
|
-
# by Ruby Symbol objects and Dictionary objects are represented by Ruby
|
|
29
|
-
# (keyed by symbols)
|
|
56
|
+
# by Ruby Symbol objects and Dictionary objects are represented by Ruby
|
|
57
|
+
# hashes (keyed by symbols)
|
|
30
58
|
#
|
|
31
|
-
#
|
|
59
|
+
# Examples:
|
|
32
60
|
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
61
|
+
# pdf_object(true) #=> "true"
|
|
62
|
+
# pdf_object(false) #=> "false"
|
|
63
|
+
# pdf_object(1.2124) #=> "1.2124"
|
|
64
|
+
# pdf_object('foo bar') #=> "(foo bar)"
|
|
65
|
+
# pdf_object(:Symbol) #=> "/Symbol"
|
|
66
|
+
# pdf_object(['foo',:bar, [1,2]]) #=> "[foo /bar [1 2]]"
|
|
39
67
|
#
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
68
|
+
# @param obj [nil, Boolean, Numeric, Array, Hash, Time, Symbol, String,
|
|
69
|
+
# PDF::Core::ByteString, PDF::Core::LiteralString,
|
|
70
|
+
# PDF::Core::NameTree::Node, PDF::Core::NameTree::Value,
|
|
71
|
+
# PDF::Core::OutlineRoot, PDF::Core::OutlineItem, PDF::Core::Reference]
|
|
72
|
+
# Object to serialise
|
|
73
|
+
# @param in_content_stream [Boolean] Specifies whther to use content stream
|
|
74
|
+
# format or object format
|
|
75
|
+
# @return [String]
|
|
76
|
+
# @raise [PDF::Core::Errors::FailedObjectConversion]
|
|
77
|
+
def pdf_object(obj, in_content_stream = false)
|
|
78
|
+
case obj
|
|
79
|
+
when NilClass then 'null'
|
|
80
|
+
when TrueClass then 'true'
|
|
81
|
+
when FalseClass then 'false'
|
|
45
82
|
when Numeric
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
end
|
|
83
|
+
num_string = obj.is_a?(Integer) ? String(obj) : real(obj)
|
|
84
|
+
|
|
85
|
+
# Truncate trailing fraction zeroes
|
|
86
|
+
num_string.sub!(/(\d*)((\.0*$)|(\.0*[1-9]*)0*$)/, '\1\4')
|
|
87
|
+
num_string
|
|
52
88
|
when Array
|
|
53
|
-
"[
|
|
89
|
+
"[#{obj.map { |e| pdf_object(e, in_content_stream) }.join(' ')}]"
|
|
54
90
|
when PDF::Core::LiteralString
|
|
55
|
-
obj = obj.gsub(/[\\\
|
|
91
|
+
obj = obj.gsub(/[\\\r()]/, STRING_ESCAPE_MAP)
|
|
56
92
|
"(#{obj})"
|
|
57
93
|
when Time
|
|
58
|
-
obj = obj.strftime(
|
|
59
|
-
obj = obj.gsub(/[\\\
|
|
94
|
+
obj = "#{obj.strftime('D:%Y%m%d%H%M%S%z').chop.chop}'00'"
|
|
95
|
+
obj = obj.gsub(/[\\\r()]/, STRING_ESCAPE_MAP)
|
|
60
96
|
"(#{obj})"
|
|
61
97
|
when PDF::Core::ByteString
|
|
62
|
-
"
|
|
98
|
+
"<#{obj.unpack1('H*')}>"
|
|
63
99
|
when String
|
|
64
100
|
obj = utf8_to_utf16(obj) unless in_content_stream
|
|
65
|
-
"
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if
|
|
69
|
-
"
|
|
101
|
+
"<#{string_to_hex(obj)}>"
|
|
102
|
+
when Symbol
|
|
103
|
+
(@symbol_str_cache ||= {})[obj] ||= (+'/') << obj.to_s.unpack('C*').map { |n|
|
|
104
|
+
if ESCAPED_NAME_CHARACTERS.include?(n)
|
|
105
|
+
"##{n.to_s(16).upcase}"
|
|
70
106
|
else
|
|
71
|
-
|
|
107
|
+
n.chr
|
|
72
108
|
end
|
|
73
|
-
|
|
109
|
+
}.join
|
|
74
110
|
when ::Hash
|
|
75
|
-
output =
|
|
76
|
-
obj
|
|
77
|
-
|
|
111
|
+
output = +'<< '
|
|
112
|
+
obj
|
|
113
|
+
.sort_by { |k, _v| k.to_s }
|
|
114
|
+
.each do |(k, v)|
|
|
115
|
+
unless k.is_a?(String) || k.is_a?(Symbol)
|
|
78
116
|
raise PDF::Core::Errors::FailedObjectConversion,
|
|
79
|
-
|
|
117
|
+
'A PDF Dictionary must be keyed by names'
|
|
80
118
|
end
|
|
81
|
-
output <<
|
|
82
|
-
|
|
119
|
+
output << pdf_object(k.to_sym, in_content_stream) << ' ' <<
|
|
120
|
+
pdf_object(v, in_content_stream) << "\n"
|
|
83
121
|
end
|
|
84
|
-
output <<
|
|
122
|
+
output << '>>'
|
|
85
123
|
when PDF::Core::Reference
|
|
86
124
|
obj.to_s
|
|
87
|
-
when PDF::Core::NameTree::Node
|
|
88
|
-
|
|
125
|
+
when PDF::Core::NameTree::Node, PDF::Core::OutlineRoot, PDF::Core::OutlineItem
|
|
126
|
+
pdf_object(obj.to_hash)
|
|
89
127
|
when PDF::Core::NameTree::Value
|
|
90
|
-
|
|
91
|
-
when PDF::Core::OutlineRoot, PDF::Core::OutlineItem
|
|
92
|
-
PdfObject(obj.to_hash)
|
|
128
|
+
"#{pdf_object(obj.name)} #{pdf_object(obj.value)}"
|
|
93
129
|
else
|
|
94
130
|
raise PDF::Core::Errors::FailedObjectConversion,
|
|
95
131
|
"This object cannot be serialized to PDF (#{obj.inspect})"
|
data/lib/pdf/core/reference.rb
CHANGED
|
@@ -1,78 +1,118 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
# reference.rb : Implementation of PDF indirect objects
|
|
4
|
-
#
|
|
5
|
-
# Copyright April 2008, Gregory Brown. All Rights Reserved.
|
|
6
|
-
#
|
|
7
|
-
# This is free software. Please see the LICENSE and COPYING files for details.
|
|
1
|
+
# frozen_string_literal: true
|
|
8
2
|
|
|
3
|
+
require 'pdf/core/utils'
|
|
9
4
|
|
|
10
5
|
module PDF
|
|
11
6
|
module Core
|
|
12
|
-
|
|
7
|
+
# PDF indirect objects
|
|
8
|
+
#
|
|
9
|
+
# @api private
|
|
10
|
+
class Reference
|
|
11
|
+
# Object identifier
|
|
12
|
+
# @return [Integer]
|
|
13
|
+
attr_accessor :identifier
|
|
14
|
+
|
|
15
|
+
# Object generation
|
|
16
|
+
# @return [Integer]
|
|
17
|
+
attr_accessor :gen
|
|
18
|
+
|
|
19
|
+
# Object data
|
|
20
|
+
# @return [any]
|
|
21
|
+
attr_accessor :data
|
|
22
|
+
|
|
23
|
+
# Offset of the serialized object in the document
|
|
24
|
+
# @return [Integer]
|
|
25
|
+
attr_accessor :offset
|
|
13
26
|
|
|
14
|
-
|
|
27
|
+
# Object stream
|
|
28
|
+
# @return [Stream]
|
|
29
|
+
attr_accessor :stream
|
|
15
30
|
|
|
31
|
+
# In PDF only dict object can have a stream attached. This exception
|
|
32
|
+
# indicates someone tried to add a stream to another kind of object.
|
|
33
|
+
class CannotAttachStream < StandardError
|
|
34
|
+
# @param message [String] Error message
|
|
35
|
+
def initialize(message = 'Cannot attach stream to a non-dictionary object')
|
|
36
|
+
super
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @param id [Integer] Object identifier
|
|
41
|
+
# @param data [any] Object data
|
|
16
42
|
def initialize(id, data)
|
|
17
43
|
@identifier = id
|
|
18
|
-
@gen
|
|
19
|
-
@data
|
|
20
|
-
@stream
|
|
44
|
+
@gen = 0
|
|
45
|
+
@data = data
|
|
46
|
+
@stream = Stream.new
|
|
21
47
|
end
|
|
22
48
|
|
|
49
|
+
# Serialized PDF object
|
|
50
|
+
#
|
|
51
|
+
# @return [String]
|
|
23
52
|
def object
|
|
24
|
-
output = "#{@identifier} #{gen} obj\n"
|
|
25
|
-
|
|
26
|
-
output << PDF::Core
|
|
53
|
+
output = +"#{@identifier} #{gen} obj\n"
|
|
54
|
+
if @stream.empty?
|
|
55
|
+
output << PDF::Core.pdf_object(data) << "\n"
|
|
27
56
|
else
|
|
28
|
-
output << PDF::Core
|
|
57
|
+
output << PDF::Core.pdf_object(data.merge(@stream.data)) <<
|
|
58
|
+
"\n" << @stream.object
|
|
29
59
|
end
|
|
30
60
|
|
|
31
61
|
output << "endobj\n"
|
|
32
62
|
end
|
|
33
63
|
|
|
64
|
+
# Appends data to object stream
|
|
65
|
+
#
|
|
66
|
+
# @param io [String] data
|
|
67
|
+
# @return [io]
|
|
68
|
+
# @raise [CannotAttachStream] if object is not a dict
|
|
34
69
|
def <<(io)
|
|
35
|
-
|
|
70
|
+
unless @data.is_a?(::Hash)
|
|
71
|
+
raise CannotAttachStream
|
|
72
|
+
end
|
|
73
|
+
|
|
36
74
|
(@stream ||= Stream.new) << io
|
|
37
75
|
end
|
|
38
76
|
|
|
77
|
+
# Object reference in PDF format
|
|
78
|
+
#
|
|
79
|
+
# @return [String]
|
|
39
80
|
def to_s
|
|
40
81
|
"#{@identifier} #{gen} R"
|
|
41
82
|
end
|
|
42
83
|
|
|
43
|
-
# Creates a deep copy of this ref.
|
|
44
|
-
# given dictionary entries between the old ref and the new.
|
|
84
|
+
# Creates a deep copy of this ref.
|
|
45
85
|
#
|
|
46
|
-
|
|
86
|
+
# @param share [Array<Symbol>] a list of dictionary entries to share
|
|
87
|
+
# between the old ref and the new
|
|
88
|
+
# @return [Reference]
|
|
89
|
+
def deep_copy(share = [])
|
|
47
90
|
r = dup
|
|
48
91
|
|
|
49
92
|
case r.data
|
|
50
93
|
when ::Hash
|
|
51
94
|
# Copy each entry not in +share+.
|
|
52
95
|
(r.data.keys - share).each do |k|
|
|
53
|
-
r.data[k] =
|
|
96
|
+
r.data[k] = Utils.deep_clone(r.data[k])
|
|
54
97
|
end
|
|
55
98
|
when PDF::Core::NameTree::Node
|
|
56
99
|
r.data = r.data.deep_copy
|
|
57
100
|
else
|
|
58
|
-
r.data =
|
|
101
|
+
r.data = Utils.deep_clone(r.data)
|
|
59
102
|
end
|
|
60
103
|
|
|
61
|
-
r.stream =
|
|
104
|
+
r.stream = Utils.deep_clone(r.stream)
|
|
62
105
|
r
|
|
63
106
|
end
|
|
64
107
|
|
|
65
108
|
# Replaces the data and stream with that of other_ref.
|
|
109
|
+
#
|
|
110
|
+
# @param other_ref [Reference]
|
|
111
|
+
# @return [void]
|
|
66
112
|
def replace(other_ref)
|
|
67
|
-
@data
|
|
113
|
+
@data = other_ref.data
|
|
68
114
|
@stream = other_ref.stream
|
|
69
115
|
end
|
|
70
116
|
end
|
|
71
|
-
|
|
72
|
-
module_function
|
|
73
|
-
|
|
74
|
-
def Reference(*args, &block) #:nodoc:
|
|
75
|
-
Reference.new(*args, &block)
|
|
76
|
-
end
|
|
77
117
|
end
|
|
78
118
|
end
|