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
data/lib/pdf/core/text.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# prawn/core/text.rb : Implements low level text helpers for Prawn
|
|
4
4
|
#
|
|
@@ -8,23 +8,47 @@
|
|
|
8
8
|
|
|
9
9
|
module PDF
|
|
10
10
|
module Core
|
|
11
|
-
|
|
11
|
+
# Low-level text rendering.
|
|
12
|
+
module Text
|
|
13
|
+
# Valid options of text drawing.
|
|
12
14
|
# These should be used as a base. Extensions may build on this list
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
VALID_OPTIONS = %i[kerning size style].freeze
|
|
16
|
+
|
|
17
|
+
# text rendering modes
|
|
18
|
+
MODES = {
|
|
19
|
+
fill: 0,
|
|
20
|
+
stroke: 1,
|
|
21
|
+
fill_stroke: 2,
|
|
22
|
+
invisible: 3,
|
|
23
|
+
fill_clip: 4,
|
|
24
|
+
stroke_clip: 5,
|
|
25
|
+
fill_stroke_clip: 6,
|
|
26
|
+
clip: 7,
|
|
27
|
+
}.freeze
|
|
28
|
+
|
|
29
|
+
# Sygnals that a font doesn't have a name.
|
|
30
|
+
class BadFontFamily < StandardError
|
|
31
|
+
def initialize(message = 'Bad font family')
|
|
32
|
+
super
|
|
33
|
+
end
|
|
34
|
+
end
|
|
18
35
|
|
|
36
|
+
# @deprecated
|
|
19
37
|
attr_reader :skip_encoding
|
|
20
38
|
|
|
21
|
-
# Low level call to set the current font style and extract text options
|
|
22
|
-
# an options hash. Should be called from within a save_font block
|
|
39
|
+
# Low level call to set the current font style and extract text options
|
|
40
|
+
# from an options hash. Should be called from within a save_font block
|
|
23
41
|
#
|
|
42
|
+
# @param options [Hash]
|
|
43
|
+
# @option options :style [Symbol, String]
|
|
44
|
+
# @option options :kerning [Boolean]
|
|
45
|
+
# @option options :size [Numeric]
|
|
46
|
+
# @return [void]
|
|
24
47
|
def process_text_options(options)
|
|
25
48
|
if options[:style]
|
|
26
|
-
raise
|
|
27
|
-
|
|
49
|
+
raise BadFontFamily unless font.family
|
|
50
|
+
|
|
51
|
+
font(font.family, style: options[:style])
|
|
28
52
|
end
|
|
29
53
|
|
|
30
54
|
# must compare against false to keep kerning on as default
|
|
@@ -37,26 +61,31 @@ module PDF
|
|
|
37
61
|
|
|
38
62
|
# Retrieve the current default kerning setting.
|
|
39
63
|
#
|
|
40
|
-
# Defaults to true
|
|
64
|
+
# Defaults to `true`.
|
|
41
65
|
#
|
|
66
|
+
# @return [Boolean]
|
|
42
67
|
def default_kerning?
|
|
43
|
-
return true
|
|
68
|
+
return true unless defined?(@default_kerning)
|
|
69
|
+
|
|
44
70
|
@default_kerning
|
|
45
71
|
end
|
|
46
72
|
|
|
47
|
-
# Call with a boolean to set the document-wide kerning setting. This can
|
|
48
|
-
# overridden using the :kerning text option when drawing text or a text
|
|
73
|
+
# Call with a boolean to set the document-wide kerning setting. This can
|
|
74
|
+
# be overridden using the :kerning text option when drawing text or a text
|
|
49
75
|
# box.
|
|
50
76
|
#
|
|
77
|
+
# @example
|
|
51
78
|
# pdf.default_kerning = false
|
|
52
|
-
# pdf.text(
|
|
53
|
-
# pdf.text(
|
|
79
|
+
# pdf.text('hello world') # text is not kerned
|
|
80
|
+
# pdf.text('hello world', kerning: true) # text is kerned
|
|
54
81
|
#
|
|
55
|
-
|
|
56
|
-
|
|
82
|
+
# @param value [Boolean]
|
|
83
|
+
# @return [void]
|
|
84
|
+
def default_kerning(value)
|
|
85
|
+
@default_kerning = value
|
|
57
86
|
end
|
|
58
87
|
|
|
59
|
-
|
|
88
|
+
alias default_kerning= default_kerning
|
|
60
89
|
|
|
61
90
|
# Call with no argument to retrieve the current default leading.
|
|
62
91
|
#
|
|
@@ -64,21 +93,24 @@ module PDF
|
|
|
64
93
|
# overridden using the :leading text option when drawing text or a text
|
|
65
94
|
# box.
|
|
66
95
|
#
|
|
96
|
+
# @example
|
|
67
97
|
# pdf.default_leading = 7
|
|
68
|
-
# pdf.text(
|
|
69
|
-
# pdf.text(
|
|
98
|
+
# pdf.text('hello world') # a leading of 7 is used
|
|
99
|
+
# pdf.text('hello world', leading: 0) # a leading of 0 is used
|
|
70
100
|
#
|
|
71
|
-
# Defaults to 0
|
|
101
|
+
# Defaults to 0.
|
|
72
102
|
#
|
|
73
|
-
|
|
103
|
+
# @param number [Numeric]
|
|
104
|
+
# @return [Numeric]
|
|
105
|
+
def default_leading(number = nil)
|
|
74
106
|
if number.nil?
|
|
75
|
-
defined?(@default_leading) && @default_leading || 0
|
|
107
|
+
(defined?(@default_leading) && @default_leading) || 0
|
|
76
108
|
else
|
|
77
109
|
@default_leading = number
|
|
78
110
|
end
|
|
79
111
|
end
|
|
80
112
|
|
|
81
|
-
|
|
113
|
+
alias default_leading= default_leading
|
|
82
114
|
|
|
83
115
|
# Call with no argument to retrieve the current text direction.
|
|
84
116
|
#
|
|
@@ -86,29 +118,33 @@ module PDF
|
|
|
86
118
|
# overridden using the :direction text option when drawing text or a text
|
|
87
119
|
# box.
|
|
88
120
|
#
|
|
121
|
+
# @example
|
|
89
122
|
# pdf.text_direction = :rtl
|
|
90
|
-
# pdf.text(
|
|
91
|
-
# pdf.text(
|
|
123
|
+
# pdf.text('hello world') # prints 'dlrow olleh'
|
|
124
|
+
# pdf.text('hello world', direction: :ltr) # prints 'hello world'
|
|
92
125
|
#
|
|
93
126
|
# Valid directions are:
|
|
94
127
|
#
|
|
95
|
-
# *
|
|
96
|
-
# *
|
|
128
|
+
# * `:ltr` -- left-to-right (default)
|
|
129
|
+
# * `:rtl` -- right-to-left
|
|
97
130
|
#
|
|
98
131
|
# Side effects:
|
|
99
132
|
#
|
|
100
|
-
# * When printing left-to-right, the default text alignment is
|
|
101
|
-
# * When printing right-to-left, the default text alignment is
|
|
133
|
+
# * When printing left-to-right, the default text alignment is `:left`
|
|
134
|
+
# * When printing right-to-left, the default text alignment is `:right`
|
|
102
135
|
#
|
|
103
|
-
|
|
136
|
+
# @param direction [:ltr, :rtl]
|
|
137
|
+
# @return [:ltr]
|
|
138
|
+
# @return [:rtl]
|
|
139
|
+
def text_direction(direction = nil)
|
|
104
140
|
if direction.nil?
|
|
105
|
-
defined?(@text_direction) && @text_direction || :ltr
|
|
141
|
+
(defined?(@text_direction) && @text_direction) || :ltr
|
|
106
142
|
else
|
|
107
143
|
@text_direction = direction
|
|
108
144
|
end
|
|
109
145
|
end
|
|
110
146
|
|
|
111
|
-
|
|
147
|
+
alias text_direction= text_direction
|
|
112
148
|
|
|
113
149
|
# Call with no argument to retrieve the current fallback fonts.
|
|
114
150
|
#
|
|
@@ -118,139 +154,297 @@ module PDF
|
|
|
118
154
|
# rendered using the first font that includes the glyph, starting with the
|
|
119
155
|
# current font and then moving through :fallback_fonts from left to right.
|
|
120
156
|
#
|
|
121
|
-
# Call with an empty array to turn off fallback fonts
|
|
122
|
-
#
|
|
123
|
-
#
|
|
124
|
-
#
|
|
125
|
-
#
|
|
126
|
-
# }
|
|
127
|
-
#
|
|
128
|
-
#
|
|
129
|
-
#
|
|
130
|
-
# }
|
|
131
|
-
#
|
|
132
|
-
#
|
|
133
|
-
#
|
|
134
|
-
#
|
|
135
|
-
#
|
|
136
|
-
#
|
|
137
|
-
#
|
|
138
|
-
#
|
|
157
|
+
# Call with an empty array to turn off fallback fonts.
|
|
158
|
+
#
|
|
159
|
+
# @example
|
|
160
|
+
# file = "#{Prawn::DATADIR}/fonts/gkai00mp.ttf"
|
|
161
|
+
# font_families['Kai'] = {
|
|
162
|
+
# normal: { file: file, font: 'Kai' }
|
|
163
|
+
# }
|
|
164
|
+
# file = "#{Prawn::DATADIR}/fonts/Action Man.dfont"
|
|
165
|
+
# font_families['Action Man'] = {
|
|
166
|
+
# normal: { file: file, font: 'ActionMan' },
|
|
167
|
+
# }
|
|
168
|
+
# fallback_fonts ['Times-Roman', 'Kai']
|
|
169
|
+
# font 'Action Man'
|
|
170
|
+
# text 'hello ƒ 你好'
|
|
171
|
+
# # hello prints in Action Man
|
|
172
|
+
# # ƒ prints in Times-Roman
|
|
173
|
+
# # 你好 prints in Kai
|
|
174
|
+
#
|
|
175
|
+
# fallback_fonts [] # clears document-wide fallback fonts
|
|
139
176
|
#
|
|
140
177
|
# Side effects:
|
|
141
178
|
#
|
|
142
179
|
# * Increased overhead when fallback fonts are declared as each glyph is
|
|
143
180
|
# checked to see whether it exists in the current font
|
|
144
181
|
#
|
|
145
|
-
|
|
182
|
+
# @param fallback_fonts [Array<String>]
|
|
183
|
+
# @return [Array<String>]
|
|
184
|
+
def fallback_fonts(fallback_fonts = nil)
|
|
146
185
|
if fallback_fonts.nil?
|
|
147
|
-
defined?(@fallback_fonts) && @fallback_fonts || []
|
|
186
|
+
(defined?(@fallback_fonts) && @fallback_fonts) || []
|
|
148
187
|
else
|
|
149
188
|
@fallback_fonts = fallback_fonts
|
|
150
189
|
end
|
|
151
190
|
end
|
|
152
191
|
|
|
153
|
-
|
|
192
|
+
alias fallback_fonts= fallback_fonts
|
|
154
193
|
|
|
155
194
|
# Call with no argument to retrieve the current text rendering mode.
|
|
156
195
|
#
|
|
157
196
|
# Call with a symbol and block to temporarily change the current
|
|
158
197
|
# text rendering mode.
|
|
159
198
|
#
|
|
199
|
+
# Valid modes are:
|
|
200
|
+
#
|
|
201
|
+
# * `:fill` - fill text (default)
|
|
202
|
+
# * `:stroke` - stroke text
|
|
203
|
+
# * `:fill_stroke` - fill, then stroke text
|
|
204
|
+
# * `:invisible` - invisible text
|
|
205
|
+
# * `:fill_clip` - fill text then add to path for clipping
|
|
206
|
+
# * `:stroke_clip` - stroke text then add to path for clipping
|
|
207
|
+
# * `:fill_stroke_clip` - fill then stroke text, then add to path for
|
|
208
|
+
# clipping
|
|
209
|
+
# * `:clip` - add text to path for clipping
|
|
210
|
+
#
|
|
211
|
+
# @example
|
|
160
212
|
# pdf.text_rendering_mode(:stroke) do
|
|
161
|
-
# pdf.text(
|
|
213
|
+
# pdf.text('Outlined Text')
|
|
162
214
|
# end
|
|
163
215
|
#
|
|
164
|
-
#
|
|
165
|
-
#
|
|
166
|
-
#
|
|
167
|
-
#
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
# * :clip - add text to path for clipping
|
|
174
|
-
def text_rendering_mode(mode=nil)
|
|
175
|
-
return (defined?(@text_rendering_mode) && @text_rendering_mode || :fill) if mode.nil?
|
|
216
|
+
# @param mode [Symbol]
|
|
217
|
+
# @yield Temporariliy set text rendering mode
|
|
218
|
+
# @return [Symbol] if called withouth mode
|
|
219
|
+
# @return [void] otherwise
|
|
220
|
+
def text_rendering_mode(mode = nil, &block)
|
|
221
|
+
if mode.nil?
|
|
222
|
+
return (defined?(@text_rendering_mode) && @text_rendering_mode) || :fill
|
|
223
|
+
end
|
|
224
|
+
|
|
176
225
|
unless MODES.key?(mode)
|
|
177
|
-
raise ArgumentError,
|
|
226
|
+
raise ArgumentError,
|
|
227
|
+
"mode must be between one of #{MODES.keys.join(', ')} (#{mode})"
|
|
178
228
|
end
|
|
179
|
-
original_mode = self.text_rendering_mode
|
|
180
229
|
|
|
181
|
-
if
|
|
230
|
+
if text_rendering_mode == mode
|
|
182
231
|
yield
|
|
183
232
|
else
|
|
184
|
-
|
|
185
|
-
add_content "\n#{MODES[mode]} Tr"
|
|
186
|
-
yield
|
|
187
|
-
add_content "\n#{MODES[original_mode]} Tr"
|
|
188
|
-
@text_rendering_mode = original_mode
|
|
233
|
+
wrap_and_restore_text_rendering_mode(mode, &block)
|
|
189
234
|
end
|
|
190
235
|
end
|
|
191
236
|
|
|
237
|
+
# Forget previously set text rendering mode.
|
|
238
|
+
#
|
|
239
|
+
# @return [void]
|
|
192
240
|
def forget_text_rendering_mode!
|
|
193
241
|
@text_rendering_mode = :unknown
|
|
194
242
|
end
|
|
195
243
|
|
|
196
244
|
# Increases or decreases the space between characters.
|
|
197
245
|
# For horizontal text, a positive value will increase the space.
|
|
198
|
-
# For
|
|
246
|
+
# For vertical text, a positive value will decrease the space.
|
|
199
247
|
#
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
248
|
+
# Call with no arguments to retrieve current character spacing.
|
|
249
|
+
#
|
|
250
|
+
# @param amount [Numeric]
|
|
251
|
+
# @yield Temporarily set character spacing
|
|
252
|
+
# @return [Numeric] if called without amount
|
|
253
|
+
# @return [void] otherwise
|
|
254
|
+
def character_spacing(amount = nil, &block)
|
|
255
|
+
if amount.nil?
|
|
256
|
+
return (defined?(@character_spacing) && @character_spacing) || 0
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
if character_spacing == amount
|
|
204
260
|
yield
|
|
205
261
|
else
|
|
206
|
-
|
|
207
|
-
add_content "\n%.3f Tc" % amount
|
|
208
|
-
yield
|
|
209
|
-
add_content "\n%.3f Tc" % original_character_spacing
|
|
210
|
-
@character_spacing = original_character_spacing
|
|
262
|
+
wrap_and_restore_character_spacing(amount, &block)
|
|
211
263
|
end
|
|
212
264
|
end
|
|
213
265
|
|
|
214
266
|
# Increases or decreases the space between words.
|
|
215
267
|
# For horizontal text, a positive value will increase the space.
|
|
216
|
-
# For
|
|
268
|
+
# For vertical text, a positive value will decrease the space.
|
|
269
|
+
#
|
|
270
|
+
# Call with no arguments to retrieve current word spacing.
|
|
217
271
|
#
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
272
|
+
# @param amount [Numeric]
|
|
273
|
+
# @yield Temporarily set word spacing
|
|
274
|
+
# @return [Numeric] if called without amount
|
|
275
|
+
# @return [void] otherwise
|
|
276
|
+
def word_spacing(amount = nil, &block)
|
|
277
|
+
return (defined?(@word_spacing) && @word_spacing) || 0 if amount.nil?
|
|
278
|
+
|
|
279
|
+
if word_spacing == amount
|
|
222
280
|
yield
|
|
223
281
|
else
|
|
224
|
-
|
|
225
|
-
|
|
282
|
+
wrap_and_restore_word_spacing(amount, &block)
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# Set the horizontal scaling.
|
|
287
|
+
#
|
|
288
|
+
# @param amount [Numeric] the percentage of the normal width.
|
|
289
|
+
# @yield Temporarili set text scaling
|
|
290
|
+
# @return [Numeric] if called with no arguments
|
|
291
|
+
# @return [void] otherwise
|
|
292
|
+
def horizontal_text_scaling(amount = nil, &block)
|
|
293
|
+
if amount.nil?
|
|
294
|
+
return (defined?(@horizontal_text_scaling) && @horizontal_text_scaling) || 100
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
if horizontal_text_scaling == amount
|
|
226
298
|
yield
|
|
227
|
-
|
|
228
|
-
|
|
299
|
+
else
|
|
300
|
+
wrap_and_restore_horizontal_text_scaling(amount, &block)
|
|
229
301
|
end
|
|
230
302
|
end
|
|
231
303
|
|
|
304
|
+
# Move the baseline up or down from its default location.
|
|
305
|
+
# Positive values move the baseline up, negative values move it down, and
|
|
306
|
+
# a zero value resets the baseline to its default location.
|
|
307
|
+
#
|
|
308
|
+
# @param amount [Numeric]
|
|
309
|
+
# @yield Temporarily set text rise
|
|
310
|
+
# @return [Numeric] if called with no arguments
|
|
311
|
+
# @return [void] otherwise
|
|
312
|
+
def rise(amount = nil, &block)
|
|
313
|
+
if amount.nil?
|
|
314
|
+
return (defined?(@rise) && @rise) || 0
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
if rise == amount
|
|
318
|
+
yield
|
|
319
|
+
else
|
|
320
|
+
wrap_and_restore_rise(amount, &block)
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
# Add a text object to content stream.
|
|
325
|
+
#
|
|
326
|
+
# @param text [String]
|
|
327
|
+
# @param x [Numeric] horizontal position of the text origin on the page
|
|
328
|
+
# @param y [Numeric] vertical position of the text origin on the page
|
|
329
|
+
# @param options [Hash]
|
|
330
|
+
# @option options :rotate [Numeric] text rotation angle in degrees
|
|
331
|
+
# @option options :kerning [Boolean]
|
|
232
332
|
def add_text_content(text, x, y, options)
|
|
233
|
-
chunks = font.encode_text(text,options)
|
|
333
|
+
chunks = font.encode_text(text, options)
|
|
234
334
|
|
|
235
|
-
add_content
|
|
335
|
+
add_content("\nBT")
|
|
236
336
|
|
|
237
337
|
if options[:rotate]
|
|
238
|
-
rad = options[:rotate]
|
|
239
|
-
|
|
240
|
-
|
|
338
|
+
rad = Float(options[:rotate]) * Math::PI / 180
|
|
339
|
+
array = [
|
|
340
|
+
Math.cos(rad),
|
|
341
|
+
Math.sin(rad),
|
|
342
|
+
-Math.sin(rad),
|
|
343
|
+
Math.cos(rad),
|
|
344
|
+
x, y,
|
|
345
|
+
]
|
|
346
|
+
add_content("#{PDF::Core.real_params(array)} Tm")
|
|
241
347
|
else
|
|
242
|
-
add_content
|
|
348
|
+
add_content("#{PDF::Core.real(x)} #{PDF::Core.real(y)} Td")
|
|
243
349
|
end
|
|
244
350
|
|
|
245
351
|
chunks.each do |(subset, string)|
|
|
246
352
|
font.add_to_current_page(subset)
|
|
247
|
-
add_content
|
|
353
|
+
add_content(
|
|
354
|
+
[
|
|
355
|
+
PDF::Core.pdf_object(font.identifier_for(subset), true),
|
|
356
|
+
PDF::Core.pdf_object(font_size, true),
|
|
357
|
+
'Tf',
|
|
358
|
+
].join(' '),
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
operation = options[:kerning] && string.is_a?(Array) ? 'TJ' : 'Tj'
|
|
362
|
+
add_content("#{PDF::Core.pdf_object(string, true)} #{operation}")
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
add_content("ET\n")
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
private
|
|
248
369
|
|
|
249
|
-
|
|
250
|
-
|
|
370
|
+
def wrap_and_restore_text_rendering_mode(block_value)
|
|
371
|
+
original_value = text_rendering_mode
|
|
372
|
+
@text_rendering_mode = block_value
|
|
373
|
+
update_text_rendering_mode_state
|
|
374
|
+
begin
|
|
375
|
+
yield
|
|
376
|
+
ensure
|
|
377
|
+
@text_rendering_mode = original_value
|
|
378
|
+
update_text_rendering_mode_state
|
|
251
379
|
end
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def update_text_rendering_mode_state
|
|
383
|
+
add_content("\n#{MODES[text_rendering_mode]} Tr")
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
def wrap_and_restore_character_spacing(block_value)
|
|
387
|
+
original_value = character_spacing
|
|
388
|
+
@character_spacing = block_value
|
|
389
|
+
update_character_spacing_state
|
|
390
|
+
begin
|
|
391
|
+
yield
|
|
392
|
+
ensure
|
|
393
|
+
@character_spacing = original_value
|
|
394
|
+
update_character_spacing_state
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
def update_character_spacing_state
|
|
399
|
+
add_content("\n#{PDF::Core.real(character_spacing)} Tc")
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
def wrap_and_restore_word_spacing(block_value)
|
|
403
|
+
original_value = word_spacing
|
|
404
|
+
@word_spacing = block_value
|
|
405
|
+
update_word_spacing_state
|
|
406
|
+
begin
|
|
407
|
+
yield
|
|
408
|
+
ensure
|
|
409
|
+
@word_spacing = original_value
|
|
410
|
+
update_word_spacing_state
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
def update_word_spacing_state
|
|
415
|
+
add_content("\n#{PDF::Core.real(word_spacing)} Tw")
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
def wrap_and_restore_horizontal_text_scaling(block_value)
|
|
419
|
+
original_value = horizontal_text_scaling
|
|
420
|
+
@horizontal_text_scaling = block_value
|
|
421
|
+
update_horizontal_text_scaling_state
|
|
422
|
+
begin
|
|
423
|
+
yield
|
|
424
|
+
ensure
|
|
425
|
+
@horizontal_text_scaling = original_value
|
|
426
|
+
update_horizontal_text_scaling_state
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
def update_horizontal_text_scaling_state
|
|
431
|
+
add_content("\n#{PDF::Core.real(horizontal_text_scaling)} Tz")
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
def wrap_and_restore_rise(block_value)
|
|
435
|
+
original_value = rise
|
|
436
|
+
@rise = block_value
|
|
437
|
+
update_rise_state
|
|
438
|
+
begin
|
|
439
|
+
yield
|
|
440
|
+
ensure
|
|
441
|
+
@rise = original_value
|
|
442
|
+
update_rise_state
|
|
443
|
+
end
|
|
444
|
+
end
|
|
252
445
|
|
|
253
|
-
|
|
446
|
+
def update_rise_state
|
|
447
|
+
add_content("\n#{PDF::Core.real(rise)} Ts")
|
|
254
448
|
end
|
|
255
449
|
end
|
|
256
450
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PDF
|
|
4
|
+
module Core
|
|
5
|
+
# Utility methods
|
|
6
|
+
module Utils
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
# Deep clone an object.
|
|
10
|
+
# It uses marshal-demarshal trick. Since it's supposed to be use only on
|
|
11
|
+
# objects that can be serialized into PDF it shouldn't have any issues
|
|
12
|
+
# with objects that can not be marshaled.
|
|
13
|
+
#
|
|
14
|
+
# @param object [any]
|
|
15
|
+
# @return [any]
|
|
16
|
+
def deep_clone(object)
|
|
17
|
+
Marshal.load(Marshal.dump(object))
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/pdf/core.rb
CHANGED
|
@@ -1,34 +1,47 @@
|
|
|
1
|
-
|
|
2
|
-
require_relative "core/annotations"
|
|
3
|
-
require_relative "core/byte_string"
|
|
4
|
-
require_relative "core/destinations"
|
|
5
|
-
require_relative "core/filters"
|
|
6
|
-
require_relative "core/stream"
|
|
7
|
-
require_relative "core/reference"
|
|
8
|
-
require_relative "core/literal_string"
|
|
9
|
-
require_relative "core/filter_list"
|
|
10
|
-
require_relative "core/page"
|
|
11
|
-
require_relative "core/object_store"
|
|
12
|
-
require_relative "core/document_state"
|
|
13
|
-
require_relative "core/name_tree"
|
|
14
|
-
require_relative "core/graphics_state"
|
|
15
|
-
require_relative "core/page_geometry"
|
|
16
|
-
require_relative "core/outline_root"
|
|
17
|
-
require_relative "core/outline_item"
|
|
18
|
-
require_relative "core/renderer"
|
|
1
|
+
# frozen_string_literal: true
|
|
19
2
|
|
|
3
|
+
# Top level Module
|
|
20
4
|
module PDF
|
|
5
|
+
# PDF::Core is concerned with low-level PDF functions such as serialization,
|
|
6
|
+
# content streams and such.
|
|
7
|
+
#
|
|
8
|
+
# It's extracted from Prawn but at the moment is not entirely independent.
|
|
21
9
|
module Core
|
|
10
|
+
# PDF::Core-specific errors
|
|
22
11
|
module Errors
|
|
23
|
-
# This error
|
|
24
|
-
FailedObjectConversion
|
|
12
|
+
# This error indicates failure of {PDF::Core.pdf_object}
|
|
13
|
+
class FailedObjectConversion < StandardError
|
|
14
|
+
end
|
|
25
15
|
|
|
26
|
-
# This error
|
|
27
|
-
|
|
16
|
+
# This error occurs when a graphic state is being restored but the graphic
|
|
17
|
+
# state stack is empty.
|
|
18
|
+
class EmptyGraphicStateStack < StandardError
|
|
19
|
+
end
|
|
28
20
|
|
|
29
|
-
# This error is raised when
|
|
30
|
-
#
|
|
31
|
-
InvalidPageLayout
|
|
21
|
+
# This error is raised when page layout is set to anything other than
|
|
22
|
+
# `:portrait` or `:landscape`
|
|
23
|
+
class InvalidPageLayout < StandardError
|
|
24
|
+
end
|
|
32
25
|
end
|
|
33
26
|
end
|
|
34
27
|
end
|
|
28
|
+
|
|
29
|
+
require_relative 'core/pdf_object'
|
|
30
|
+
require_relative 'core/annotations'
|
|
31
|
+
require_relative 'core/byte_string'
|
|
32
|
+
require_relative 'core/destinations'
|
|
33
|
+
require_relative 'core/filters'
|
|
34
|
+
require_relative 'core/stream'
|
|
35
|
+
require_relative 'core/reference'
|
|
36
|
+
require_relative 'core/literal_string'
|
|
37
|
+
require_relative 'core/filter_list'
|
|
38
|
+
require_relative 'core/page'
|
|
39
|
+
require_relative 'core/object_store'
|
|
40
|
+
require_relative 'core/document_state'
|
|
41
|
+
require_relative 'core/name_tree'
|
|
42
|
+
require_relative 'core/graphics_state'
|
|
43
|
+
require_relative 'core/page_geometry'
|
|
44
|
+
require_relative 'core/outline_root'
|
|
45
|
+
require_relative 'core/outline_item'
|
|
46
|
+
require_relative 'core/renderer'
|
|
47
|
+
require_relative 'core/text'
|