origami 1.0.4 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +40 -49
- data/bin/gui/about.rb +1 -1
- data/bin/pdfencrypt +10 -4
- data/origami/actions.rb +0 -1
- data/origami/docmdp.rb +96 -0
- data/origami/encryption.rb +103 -14
- data/origami/graphics.rb +1 -0
- data/origami/graphics/colors.rb +23 -23
- data/origami/graphics/instruction.rb +7 -29
- data/origami/graphics/path.rb +53 -19
- data/origami/graphics/render.rb +69 -0
- data/origami/graphics/state.rb +9 -9
- data/origami/graphics/text.rb +66 -48
- data/origami/graphics/xobject.rb +65 -50
- data/origami/javascript.rb +135 -0
- data/origami/metadata.rb +24 -0
- data/origami/object.rb +1 -1
- data/origami/page.rb +12 -0
- data/origami/parsers/pdf/linear.rb +0 -0
- data/origami/pdf.rb +2 -2
- metadata +77 -75
- data/VERSION +0 -1
data/origami/graphics.rb
CHANGED
data/origami/graphics/colors.rb
CHANGED
@@ -24,7 +24,7 @@
|
|
24
24
|
=end
|
25
25
|
|
26
26
|
begin
|
27
|
-
require 'color'
|
27
|
+
require 'color'
|
28
28
|
rescue LoadError
|
29
29
|
end
|
30
30
|
|
@@ -118,73 +118,73 @@ module Origami
|
|
118
118
|
|
119
119
|
class PDF::Instruction
|
120
120
|
|
121
|
-
insn 'CS', Name do |
|
122
|
-
insn 'cs', Name do |
|
123
|
-
insn 'SC', '*' do |
|
124
|
-
insn 'sc', '*' do |
|
121
|
+
insn 'CS', Name do |canvas, cs| canvas.gs.stroking_colorspace = cs end
|
122
|
+
insn 'cs', Name do |canvas, cs| canvas.gs.nonstroking_colorspace = cs end
|
123
|
+
insn 'SC', '*' do |canvas, *c| canvas.gs.stroking_color = c end
|
124
|
+
insn 'sc', '*' do |canvas, *c| canvas.gs.nonstroking_color = c end
|
125
125
|
|
126
|
-
insn 'G', Real do |
|
126
|
+
insn 'G', Real do |canvas, c|
|
127
127
|
unless (0..1).include? c
|
128
128
|
raise Graphics::InvalidColorError,
|
129
129
|
"Not a valid color for DeviceGray: #{c}"
|
130
130
|
end
|
131
131
|
|
132
|
-
gs.stroking_colorspace = Graphics::Color::Space::DEVICE_GRAY
|
133
|
-
gs.stroking_color = [ c ]
|
132
|
+
canvas.gs.stroking_colorspace = Graphics::Color::Space::DEVICE_GRAY
|
133
|
+
canvas.gs.stroking_color = [ c ]
|
134
134
|
end
|
135
135
|
|
136
|
-
insn 'g', Real do |
|
136
|
+
insn 'g', Real do |canvas, c|
|
137
137
|
unless (0..1).include? c
|
138
138
|
raise Graphics::InvalidColorError,
|
139
139
|
"Not a valid color for DeviceGray: #{c}"
|
140
140
|
end
|
141
141
|
|
142
|
-
gs.nonstroking_colorspace = Graphics::Color::Space::DEVICE_GRAY
|
143
|
-
gs.nonstroking_color = [ c ]
|
142
|
+
canvas.gs.nonstroking_colorspace = Graphics::Color::Space::DEVICE_GRAY
|
143
|
+
canvas.gs.nonstroking_color = [ c ]
|
144
144
|
end
|
145
145
|
|
146
|
-
insn 'RG', Real, Real, Real do |
|
146
|
+
insn 'RG', Real, Real, Real do |canvas, r,g,b|
|
147
147
|
c = [ r, g, b ]
|
148
148
|
unless c.all? {|b| (0..1).include? b}
|
149
149
|
raise Graphics::InvalidColorError,
|
150
150
|
"Not a valid color for DeviceRGB: #{c.inspect}"
|
151
151
|
end
|
152
152
|
|
153
|
-
gs.stroking_colorspace = Graphics::Color::Space::DEVICE_RGB
|
154
|
-
gs.stroking_color = c
|
153
|
+
canvas.gs.stroking_colorspace = Graphics::Color::Space::DEVICE_RGB
|
154
|
+
canvas.gs.stroking_color = c
|
155
155
|
end
|
156
156
|
|
157
|
-
insn 'rg', Real, Real, Real do |
|
157
|
+
insn 'rg', Real, Real, Real do |canvas, r,g,b|
|
158
158
|
c = [ r, g, b ]
|
159
159
|
unless c.all? {|b| (0..1).include? b}
|
160
160
|
raise Graphics::InvalidColorError,
|
161
161
|
"Not a valid color for DeviceRGB: #{c.inspect}"
|
162
162
|
end
|
163
163
|
|
164
|
-
gs.nonstroking_colorspace = Graphics::Color::Space::DEVICE_RGB
|
165
|
-
gs.nonstroking_color = c
|
164
|
+
canvas.gs.nonstroking_colorspace = Graphics::Color::Space::DEVICE_RGB
|
165
|
+
canvas.gs.nonstroking_color = c
|
166
166
|
end
|
167
167
|
|
168
|
-
insn 'K', Real, Real, Real, Real do |
|
168
|
+
insn 'K', Real, Real, Real, Real do |canvas, c,m,y,k|
|
169
169
|
c = [ c, m, y, k ]
|
170
170
|
unless c.all? {|b| (0..1).include? b}
|
171
171
|
raise Graphics::InvalidColorError,
|
172
172
|
"Not a valid color for DeviceCMYK: #{c.inspect}"
|
173
173
|
end
|
174
174
|
|
175
|
-
gs.stroking_colorspace = Graphics::Color::Space::DEVICE_CMYK
|
176
|
-
gs.stroking_color = c
|
175
|
+
canvas.gs.stroking_colorspace = Graphics::Color::Space::DEVICE_CMYK
|
176
|
+
canvas.gs.stroking_color = c
|
177
177
|
end
|
178
178
|
|
179
|
-
insn 'k', Real, Real, Real, Real do |
|
179
|
+
insn 'k', Real, Real, Real, Real do |canvas, c,m,y,k|
|
180
180
|
c = [ c, m, y, k ]
|
181
181
|
unless c.all? {|b| (0..1).include? b}
|
182
182
|
raise Graphics::InvalidColorError,
|
183
183
|
"Not a valid color for DeviceCMYK: #{c.inspect}"
|
184
184
|
end
|
185
185
|
|
186
|
-
gs.nonstroking_colorspace = Graphics::Color::Space::DEVICE_CMYK
|
187
|
-
gs.nonstroking_color = c
|
186
|
+
canvas.gs.nonstroking_colorspace = Graphics::Color::Space::DEVICE_CMYK
|
187
|
+
canvas.gs.nonstroking_color = c
|
188
188
|
end
|
189
189
|
end
|
190
190
|
|
@@ -31,7 +31,7 @@ module Origami
|
|
31
31
|
attr_accessor :operands
|
32
32
|
|
33
33
|
@@regexp = Regexp.new('([^ \\t\\r\\n\\0\\[\\]<>()%\\/]+)')
|
34
|
-
@insns = Hash.new(:operands => [], :
|
34
|
+
@insns = Hash.new(:operands => [], :render => lambda{})
|
35
35
|
|
36
36
|
def initialize(operator, *operands)
|
37
37
|
@operator = operator
|
@@ -47,17 +47,8 @@ module Origami
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
def
|
51
|
-
self.class.
|
52
|
-
self
|
53
|
-
end
|
54
|
-
|
55
|
-
def render
|
56
|
-
end
|
57
|
-
|
58
|
-
def exec(gs)
|
59
|
-
update_state(gs)
|
60
|
-
self.class.get_callback(@operator)[gs] if self.class.has_callback?(@operator)
|
50
|
+
def render(canvas)
|
51
|
+
self.class.get_render_proc(@operator)[canvas, *@operands]
|
61
52
|
|
62
53
|
self
|
63
54
|
end
|
@@ -67,31 +58,18 @@ module Origami
|
|
67
58
|
end
|
68
59
|
|
69
60
|
class << self
|
70
|
-
def insn(operator, *operands, &
|
61
|
+
def insn(operator, *operands, &render_proc)
|
71
62
|
@insns[operator] = {}
|
72
63
|
@insns[operator][:operands] = operands
|
73
|
-
@insns[operator][:
|
64
|
+
@insns[operator][:render] = render_proc || lambda{}
|
74
65
|
end
|
75
66
|
|
76
67
|
def has_op?(operator)
|
77
68
|
@insns.has_key? operator
|
78
69
|
end
|
79
70
|
|
80
|
-
def
|
81
|
-
|
82
|
-
end
|
83
|
-
|
84
|
-
def has_callback?(operator)
|
85
|
-
self.has_op?(operator) and @insns[operator].has_key?(:callback)
|
86
|
-
end
|
87
|
-
|
88
|
-
def set_callback(operator, &b)
|
89
|
-
raise RuntimeError, "Operator `#{operator}' does not exist" unless @insns.has_key?(operator)
|
90
|
-
@insns[operator][:callback] = b
|
91
|
-
end
|
92
|
-
|
93
|
-
def get_proc(operator)
|
94
|
-
@insns[operator][:proc]
|
71
|
+
def get_render_proc(operator)
|
72
|
+
@insns[operator][:render]
|
95
73
|
end
|
96
74
|
|
97
75
|
def get_operands(operator)
|
data/origami/graphics/path.rb
CHANGED
@@ -105,49 +105,83 @@ module Origami
|
|
105
105
|
end
|
106
106
|
|
107
107
|
class PDF::Instruction
|
108
|
-
insn 'm', Real, Real do |
|
109
|
-
gs.current_path << (subpath = Graphics::Path.new)
|
108
|
+
insn 'm', Real, Real do |canvas, x,y|
|
109
|
+
canvas.gs.current_path << (subpath = Graphics::Path.new)
|
110
110
|
subpath.current_point = [x,y]
|
111
111
|
end
|
112
112
|
|
113
|
-
insn 'l', Real, Real do |
|
114
|
-
if gs.current_path.empty?
|
113
|
+
insn 'l', Real, Real do |canvas, x,y|
|
114
|
+
if canvas.gs.current_path.empty?
|
115
115
|
raise InvalidPathError, "No current point is defined"
|
116
116
|
end
|
117
117
|
|
118
|
-
subpath = gs.current_path.last
|
118
|
+
subpath = canvas.gs.current_path.last
|
119
119
|
|
120
120
|
from = subpath.current_point
|
121
121
|
to = [x,y]
|
122
122
|
subpath.add_segment(Graphics::Path::Line.new(from, to))
|
123
123
|
end
|
124
124
|
|
125
|
-
insn 'h' do |
|
126
|
-
unless gs.current_path.empty?
|
127
|
-
subpath = gs.current_path.last
|
125
|
+
insn 'h' do |canvas|
|
126
|
+
unless canvas.gs.current_path.empty?
|
127
|
+
subpath = canvas.gs.current_path.last
|
128
128
|
subpath.close! unless subpath.is_closed?
|
129
129
|
end
|
130
130
|
end
|
131
131
|
|
132
|
-
insn 're', Real, Real, Real, Real do |
|
132
|
+
insn 're', Real, Real, Real, Real do |canvas, x,y,width,height|
|
133
133
|
tx = x + width
|
134
134
|
ty = y + height
|
135
|
-
gs.current_path << (subpath = Graphics::Path.new)
|
135
|
+
canvas.gs.current_path << (subpath = Graphics::Path.new)
|
136
136
|
subpath.segments << Graphics::Path::Line.new([x,y], [tx,y])
|
137
137
|
subpath.segments << Graphics::Path::Line.new([tx,y], [tx, ty])
|
138
138
|
subpath.segments << Graphics::Path::Line.new([tx, ty], [x, ty])
|
139
139
|
subpath.close!
|
140
140
|
end
|
141
141
|
|
142
|
-
insn 'S'
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
insn '
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
142
|
+
insn 'S' do |canvas|
|
143
|
+
canvas.stroke_path
|
144
|
+
end
|
145
|
+
|
146
|
+
insn 's' do |canvas|
|
147
|
+
canvas.gs.current_path.last.close!
|
148
|
+
canvas.stroke_path
|
149
|
+
end
|
150
|
+
|
151
|
+
insn 'f' do |canvas|
|
152
|
+
canvas.fill_path
|
153
|
+
end
|
154
|
+
|
155
|
+
insn 'F' do |canvas|
|
156
|
+
canvas.fill_path
|
157
|
+
end
|
158
|
+
|
159
|
+
insn 'f*' do |canvas|
|
160
|
+
canvas.fill_path
|
161
|
+
end
|
162
|
+
|
163
|
+
insn 'B' do |canvas|
|
164
|
+
canvas.fill_path
|
165
|
+
canvas.stroke_path
|
166
|
+
end
|
167
|
+
|
168
|
+
insn 'B*' do |canvas|
|
169
|
+
canvas.fill_path
|
170
|
+
canvas.stroke_path
|
171
|
+
end
|
172
|
+
|
173
|
+
insn 'b' do |canvas|
|
174
|
+
canvas.gs.current_path.last.close!
|
175
|
+
canvas.fill_path
|
176
|
+
canvas.stroke_path
|
177
|
+
end
|
178
|
+
|
179
|
+
insn 'b*' do |canvas|
|
180
|
+
canvas.gs.current_path.last.close!
|
181
|
+
canvas.fill_path
|
182
|
+
canvas.stroke_path
|
183
|
+
end
|
184
|
+
|
151
185
|
insn 'n'
|
152
186
|
end
|
153
187
|
|
@@ -0,0 +1,69 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
= File
|
4
|
+
graphics/render.rb
|
5
|
+
|
6
|
+
= Info
|
7
|
+
This file is part of Origami, PDF manipulation framework for Ruby
|
8
|
+
Copyright (C) 2010 Guillaume Delugré <guillaume@security-labs.org>
|
9
|
+
All right reserved.
|
10
|
+
|
11
|
+
Origami is free software: you can redistribute it and/or modify
|
12
|
+
it under the terms of the GNU Lesser General Public License as published by
|
13
|
+
the Free Software Foundation, either version 3 of the License, or
|
14
|
+
(at your option) any later version.
|
15
|
+
|
16
|
+
Origami is distributed in the hope that it will be useful,
|
17
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
18
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
19
|
+
GNU Lesser General Public License for more details.
|
20
|
+
|
21
|
+
You should have received a copy of the GNU Lesser General Public License
|
22
|
+
along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
23
|
+
|
24
|
+
=end
|
25
|
+
|
26
|
+
module Origami
|
27
|
+
|
28
|
+
module Graphics
|
29
|
+
|
30
|
+
module Canvas
|
31
|
+
attr_reader :gs
|
32
|
+
|
33
|
+
def initialize
|
34
|
+
@gs = Graphics::State.new
|
35
|
+
end
|
36
|
+
|
37
|
+
def clear
|
38
|
+
@gs.reset
|
39
|
+
end
|
40
|
+
|
41
|
+
def write_text(s); end
|
42
|
+
def stroke_path; end
|
43
|
+
def fill_path; end
|
44
|
+
end
|
45
|
+
|
46
|
+
class DummyCanvas
|
47
|
+
include Canvas
|
48
|
+
end
|
49
|
+
|
50
|
+
class TextCanvas
|
51
|
+
include Canvas
|
52
|
+
|
53
|
+
def initialize(output = STDOUT, columns = 80, lines = 25)
|
54
|
+
super()
|
55
|
+
|
56
|
+
@output = output
|
57
|
+
@columns, @lines = columns, lines
|
58
|
+
end
|
59
|
+
|
60
|
+
def write_text(s)
|
61
|
+
@output.print(s)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
data/origami/graphics/state.rb
CHANGED
@@ -147,18 +147,18 @@ module Origami
|
|
147
147
|
end #module Graphics
|
148
148
|
|
149
149
|
class PDF::Instruction
|
150
|
-
insn 'q' do |
|
151
|
-
insn 'Q' do |
|
152
|
-
insn 'w', Real do |
|
153
|
-
insn 'J', Real do |
|
154
|
-
insn 'j', Real do |
|
155
|
-
insn 'M', Real do |
|
150
|
+
insn 'q' do |canvas| canvas.gs.save; canvas.gs.reset end
|
151
|
+
insn 'Q' do |canvas| canvas.gs.restore end
|
152
|
+
insn 'w', Real do |canvas, lw| canvas.gs.line_width = lw end
|
153
|
+
insn 'J', Real do |canvas, lc| canvas.gs.line_cap = lc end
|
154
|
+
insn 'j', Real do |canvas, lj| canvas.gs.line_join = lj end
|
155
|
+
insn 'M', Real do |canvas, ml| canvas.gs.miter_limit = ml end
|
156
156
|
|
157
|
-
insn 'd', Array, Integer do |
|
158
|
-
gs.dash_pattern = Graphics::DashPattern.new array, phase
|
157
|
+
insn 'd', Array, Integer do |canvas, array, phase|
|
158
|
+
canvas.gs.dash_pattern = Graphics::DashPattern.new array, phase
|
159
159
|
end
|
160
160
|
|
161
|
-
insn 'ri', Name do |
|
161
|
+
insn 'ri', Name do |canvas, ri| canvas.gs.rendering_intent = ri end
|
162
162
|
end
|
163
163
|
end
|
164
164
|
|
data/origami/graphics/text.rb
CHANGED
@@ -119,106 +119,124 @@ module Origami
|
|
119
119
|
|
120
120
|
class PDF::Instruction
|
121
121
|
# Text instructions definitions
|
122
|
-
insn 'Tc', Real do |
|
123
|
-
insn 'Tw', Real do |
|
124
|
-
insn 'Tz', Real do |
|
125
|
-
insn 'TL', Real do |
|
122
|
+
insn 'Tc', Real do |canvas, cS| canvas.gs.text_state.char_spacing = cS end
|
123
|
+
insn 'Tw', Real do |canvas, wS| canvas.gs.text_state.word_spacing = wS end
|
124
|
+
insn 'Tz', Real do |canvas, s| canvas.gs.text_state.scaling = s end
|
125
|
+
insn 'TL', Real do |canvas, l| canvas.gs.text_state.leading = l end
|
126
126
|
|
127
|
-
insn 'Tf', Name, Real do |
|
128
|
-
gs.text_state.font = font
|
129
|
-
gs.text_state.font_size = size
|
127
|
+
insn 'Tf', Name, Real do |canvas, font, size|
|
128
|
+
canvas.gs.text_state.font = font
|
129
|
+
canvas.gs.text_state.font_size = size
|
130
130
|
end
|
131
131
|
|
132
|
-
insn 'Tr', Integer do |
|
133
|
-
insn 'Ts', Real do |
|
134
|
-
insn 'BT' do |
|
135
|
-
insn 'ET' do |
|
132
|
+
insn 'Tr', Integer do |canvas, r| canvas.gs.text_state.rendering_mode = r end
|
133
|
+
insn 'Ts', Real do |canvas, s| canvas.gs.text_state.text_rise = s end
|
134
|
+
insn 'BT' do |canvas| canvas.gs.text_state.begin_text_object end
|
135
|
+
insn 'ET' do |canvas| canvas.gs.text_state.end_text_object end
|
136
136
|
|
137
|
-
insn 'Td', Real, Real do |
|
138
|
-
unless gs.text_state.is_in_text_object?
|
137
|
+
insn 'Td', Real, Real do |canvas, tx, ty|
|
138
|
+
unless canvas.gs.text_state.is_in_text_object?
|
139
139
|
raise TextStateError,
|
140
140
|
"Must be in a text object to use operator : Td"
|
141
141
|
end
|
142
142
|
|
143
|
-
gs.text_state.text_matrix =
|
144
|
-
gs.text_state.text_line_matrix =
|
145
|
-
Matrix.rows([[1,0,0],[0,1,0],[tx, ty, 1]]) * gs.text_state.text_line_matrix
|
143
|
+
canvas.gs.text_state.text_matrix =
|
144
|
+
canvas.gs.text_state.text_line_matrix =
|
145
|
+
Matrix.rows([[1,0,0],[0,1,0],[tx, ty, 1]]) * canvas.gs.text_state.text_line_matrix
|
146
146
|
end
|
147
147
|
|
148
|
-
insn 'TD', Real, Real do |
|
149
|
-
unless gs.text_state.is_in_text_object?
|
148
|
+
insn 'TD', Real, Real do |canvas, tx, ty|
|
149
|
+
unless canvas.gs.text_state.is_in_text_object?
|
150
150
|
raise TextStateError,
|
151
151
|
"Must be in a text object to use operator : TD"
|
152
152
|
end
|
153
153
|
|
154
|
-
gs.text_state.leading = -ty
|
154
|
+
canvas.gs.text_state.leading = -ty
|
155
155
|
|
156
|
-
gs.text_state.text_matrix =
|
157
|
-
gs.text_state.text_line_matrix =
|
158
|
-
Matrix.rows([[1,0,0],[0,1,0],[tx,ty,1]]) * gs.text_state.text_line_matrix
|
156
|
+
canvas.gs.text_state.text_matrix =
|
157
|
+
canvas.gs.text_state.text_line_matrix =
|
158
|
+
Matrix.rows([[1,0,0],[0,1,0],[tx,ty,1]]) * canvas.gs.text_state.text_line_matrix
|
159
159
|
end
|
160
160
|
|
161
|
-
insn 'Tm', Real, Real, Real, Real, Real, Real do |
|
162
|
-
unless gs.text_state.is_in_text_object?
|
161
|
+
insn 'Tm', Real, Real, Real, Real, Real, Real do |canvas, a,b,c,d,e,f,g|
|
162
|
+
unless canvas.gs.text_state.is_in_text_object?
|
163
163
|
raise TextStateError,
|
164
164
|
"Must be in a text object to use operator : Tm"
|
165
165
|
end
|
166
166
|
|
167
|
-
gs.text_state.text_matrix =
|
168
|
-
gs.text_state.text_line_matrix =
|
167
|
+
canvas.gs.text_state.text_matrix =
|
168
|
+
canvas.gs.text_state.text_line_matrix =
|
169
169
|
Matrix.rows([[a,b,0],[c,d,0],[e,f,1]])
|
170
170
|
end
|
171
171
|
|
172
|
-
insn 'T*' do |
|
173
|
-
unless gs.text_state.is_in_text_object?
|
172
|
+
insn 'T*' do |canvas|
|
173
|
+
unless canvas.gs.text_state.is_in_text_object?
|
174
174
|
raise TextStateError,
|
175
175
|
"Must be in a text object to use operator : T*"
|
176
176
|
end
|
177
177
|
|
178
|
-
tx, ty = 0, -gs.text_state.leading
|
178
|
+
tx, ty = 0, -canvas.gs.text_state.leading
|
179
179
|
|
180
|
-
gs.text_state.text_matrix =
|
181
|
-
gs.text_state.text_line_matrix =
|
182
|
-
Matrix.rows([[1,0,0],[0,1,0],[tx, ty, 1]]) * gs.text_state.text_line_matrix
|
180
|
+
canvas.gs.text_state.text_matrix =
|
181
|
+
canvas.gs.text_state.text_line_matrix =
|
182
|
+
Matrix.rows([[1,0,0],[0,1,0],[tx, ty, 1]]) * canvas.gs.text_state.text_line_matrix
|
183
183
|
end
|
184
184
|
|
185
|
-
insn 'Tj', String do |
|
186
|
-
unless gs.text_state.is_in_text_object?
|
185
|
+
insn 'Tj', String do |canvas, s|
|
186
|
+
unless canvas.gs.text_state.is_in_text_object?
|
187
187
|
raise TextStateError,
|
188
188
|
"Must be in a text object to use operator : Tj"
|
189
189
|
end
|
190
|
+
|
191
|
+
canvas.write_text(s)
|
190
192
|
end
|
191
193
|
|
192
|
-
insn "'", String do |
|
193
|
-
unless gs.text_state.is_in_text_object?
|
194
|
+
insn "'", String do |canvas, s|
|
195
|
+
unless canvas.gs.text_state.is_in_text_object?
|
194
196
|
raise TextStateError,
|
195
197
|
"Must be in a text object to use operator : '"
|
196
198
|
end
|
197
199
|
|
198
|
-
tx, ty = 0, -gs.text_state.leading
|
200
|
+
tx, ty = 0, -canvas.gs.text_state.leading
|
201
|
+
|
202
|
+
canvas.gs.text_state.text_matrix =
|
203
|
+
canvas.gs.text_state.text_line_matrix =
|
204
|
+
Matrix.rows([[1,0,0],[0,1,0],[tx, ty, 1]]) * canvas.gs.text_state.text_line_matrix
|
199
205
|
|
200
|
-
|
201
|
-
gs.text_state.text_line_matrix =
|
202
|
-
Matrix.rows([[1,0,0],[0,1,0],[tx, ty, 1]]) * gs.text_state.text_line_matrix
|
206
|
+
canvas.write_text(s)
|
203
207
|
end
|
204
208
|
|
205
|
-
insn '"', Real, Real, String do |
|
206
|
-
unless gs.text_state.is_in_text_object?
|
209
|
+
insn '"', Real, Real, String do |canvas, w, c, s|
|
210
|
+
unless canvas.gs.text_state.is_in_text_object?
|
207
211
|
raise TextStateError,
|
208
212
|
"Must be in a text object to use operator : \""
|
209
213
|
end
|
210
214
|
|
211
|
-
gs.text_state.word_spacing = w
|
212
|
-
gs.text_state.char_spacing = c
|
215
|
+
canvas.gs.text_state.word_spacing = w
|
216
|
+
canvas.gs.text_state.char_spacing = c
|
213
217
|
|
214
218
|
tx, ty = 0, -gs.text_state.leading
|
215
219
|
|
216
|
-
gs.text_state.text_matrix =
|
217
|
-
gs.text_state.text_line_matrix =
|
218
|
-
Matrix.rows([[1,0,0],[0,1,0],[tx, ty, 1]]) * gs.text_state.text_line_matrix
|
220
|
+
canvas.gs.text_state.text_matrix =
|
221
|
+
canvas.gs.text_state.text_line_matrix =
|
222
|
+
Matrix.rows([[1,0,0],[0,1,0],[tx, ty, 1]]) * canvas.gs.text_state.text_line_matrix
|
223
|
+
|
224
|
+
canvas.write_text(s)
|
219
225
|
end
|
220
226
|
|
221
|
-
insn 'TJ', Array
|
227
|
+
insn 'TJ', Array do |canvas, arr|
|
228
|
+
arr.each do |g|
|
229
|
+
case g
|
230
|
+
when Fixnum,Float then
|
231
|
+
# XXX: handle this in text space ?
|
232
|
+
when ::String then
|
233
|
+
canvas.write_text(g)
|
234
|
+
else
|
235
|
+
raise InvalidPDFInstructionError,
|
236
|
+
"Invalid component type `#{g.class}` in TJ operand"
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
222
240
|
end
|
223
241
|
|
224
242
|
end
|