postsvg 0.2.2 → 0.3.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 +4 -4
- data/.rubocop_todo.yml +49 -533
- data/Gemfile +1 -1
- data/lib/postsvg/cli.rb +5 -10
- data/lib/postsvg/color.rb +132 -0
- data/lib/postsvg/format_number.rb +22 -0
- data/lib/postsvg/graphics_context.rb +1 -2
- data/lib/postsvg/matrix.rb +106 -0
- data/lib/postsvg/model/literals/array.rb +41 -0
- data/lib/postsvg/model/literals/dictionary.rb +34 -0
- data/lib/postsvg/model/literals/hex.rb +37 -0
- data/lib/postsvg/model/literals/name.rb +40 -0
- data/lib/postsvg/model/literals/number.rb +36 -0
- data/lib/postsvg/model/literals/procedure.rb +41 -0
- data/lib/postsvg/model/literals/string.rb +30 -0
- data/lib/postsvg/model/literals.rb +19 -0
- data/lib/postsvg/model/operator.rb +58 -0
- data/lib/postsvg/model/operators/arithmetic.rb +264 -0
- data/lib/postsvg/model/operators/boolean.rb +182 -0
- data/lib/postsvg/model/operators/color.rb +74 -0
- data/lib/postsvg/model/operators/container.rb +186 -0
- data/lib/postsvg/model/operators/control_flow.rb +119 -0
- data/lib/postsvg/model/operators/device.rb +21 -0
- data/lib/postsvg/model/operators/dictionary.rb +118 -0
- data/lib/postsvg/model/operators/font.rb +121 -0
- data/lib/postsvg/model/operators/graphics_state.rb +84 -0
- data/lib/postsvg/model/operators/painting.rb +29 -0
- data/lib/postsvg/model/operators/path.rb +169 -0
- data/lib/postsvg/model/operators/stack.rb +72 -0
- data/lib/postsvg/model/operators/transformations.rb +103 -0
- data/lib/postsvg/model/operators.rb +89 -0
- data/lib/postsvg/model/program.rb +68 -0
- data/lib/postsvg/model/token.rb +43 -0
- data/lib/postsvg/model.rb +17 -0
- data/lib/postsvg/options.rb +1 -1
- data/lib/postsvg/parser/postscript_parser.rb +7 -7
- data/lib/postsvg/renderer.rb +3 -7
- data/lib/postsvg/serializer.rb +325 -0
- data/lib/postsvg/source/ast_builder.rb +308 -0
- data/lib/postsvg/source/lexer.rb +322 -0
- data/lib/postsvg/source/operand_stack.rb +55 -0
- data/lib/postsvg/source.rb +21 -0
- data/lib/postsvg/svg/clip_path_registry.rb +1 -3
- data/lib/postsvg/svg/element.rb +1 -3
- data/lib/postsvg/svg/elements/ellipse.rb +1 -2
- data/lib/postsvg/svg/elements/svg.rb +1 -2
- data/lib/postsvg/svg/paint.rb +1 -1
- data/lib/postsvg/svg/path_data/parser.rb +6 -10
- data/lib/postsvg/svg/stroke.rb +2 -4
- data/lib/postsvg/svg/transform_list.rb +1 -1
- data/lib/postsvg/svg_builder.rb +11 -15
- data/lib/postsvg/translation/arc_converter.rb +12 -22
- data/lib/postsvg/translation/bounding_box.rb +4 -7
- data/lib/postsvg/translation/handlers/circle_handler.rb +2 -2
- data/lib/postsvg/translation/handlers/ellipse_handler.rb +3 -8
- data/lib/postsvg/translation/handlers/group_handler.rb +1 -2
- data/lib/postsvg/translation/handlers/image_handler.rb +2 -3
- data/lib/postsvg/translation/handlers/line_handler.rb +2 -6
- data/lib/postsvg/translation/handlers/open_handler.rb +2 -3
- data/lib/postsvg/translation/handlers/path_handler.rb +41 -57
- data/lib/postsvg/translation/handlers/polygon_handler.rb +2 -4
- data/lib/postsvg/translation/handlers/polyline_handler.rb +2 -4
- data/lib/postsvg/translation/handlers/rect_handler.rb +5 -10
- data/lib/postsvg/translation/handlers/shared.rb +11 -11
- data/lib/postsvg/translation/handlers/svg_handler.rb +2 -3
- data/lib/postsvg/translation/handlers/text_handler.rb +7 -8
- data/lib/postsvg/translation/handlers.rb +1 -2
- data/lib/postsvg/translation/ps_renderer.rb +1 -2
- data/lib/postsvg/version.rb +1 -1
- data/lib/postsvg/visitors/ps_visitor/arithmetic.rb +6 -6
- data/lib/postsvg/visitors/ps_visitor/color.rb +5 -8
- data/lib/postsvg/visitors/ps_visitor/common.rb +2 -1
- data/lib/postsvg/visitors/ps_visitor/container.rb +13 -13
- data/lib/postsvg/visitors/ps_visitor/control_flow.rb +3 -3
- data/lib/postsvg/visitors/ps_visitor/dictionary.rb +4 -8
- data/lib/postsvg/visitors/ps_visitor/font.rb +4 -14
- data/lib/postsvg/visitors/ps_visitor/graphics_state.rb +4 -4
- data/lib/postsvg/visitors/ps_visitor/painting.rb +1 -1
- data/lib/postsvg/visitors/ps_visitor/path.rb +4 -9
- data/lib/postsvg.rb +37 -42
- metadata +36 -16
|
@@ -17,14 +17,9 @@ module Postsvg
|
|
|
17
17
|
# Approximate ellipse with scale + arc.
|
|
18
18
|
if rx.to_f.positive? && ry.to_f.positive?
|
|
19
19
|
scale = rx / ry
|
|
20
|
-
context.emitter.emit(Model::Operators::Transformations::Translate.new(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
context.emitter.emit(Model::Operators::Transformations::Scale.new(
|
|
24
|
-
sx: scale, sy: 1,
|
|
25
|
-
))
|
|
26
|
-
context.emitter.emit(Model::Operators::Path::Arc.new(x: 0, y: 0,
|
|
27
|
-
radius: ry, angle1: 0, angle2: 360))
|
|
20
|
+
context.emitter.emit(Model::Operators::Transformations::Translate.new(tx: cx, ty: cy))
|
|
21
|
+
context.emitter.emit(Model::Operators::Transformations::Scale.new(sx: scale, sy: 1))
|
|
22
|
+
context.emitter.emit(Model::Operators::Path::Arc.new(x: 0, y: 0, radius: ry, angle1: 0, angle2: 360))
|
|
28
23
|
end
|
|
29
24
|
emit_paint(element, context)
|
|
30
25
|
context.emitter.emit(Model::Operators::GraphicsState::Grestore.new)
|
|
@@ -11,8 +11,7 @@ module Postsvg
|
|
|
11
11
|
emit_transform(element, context)
|
|
12
12
|
emit_paint_setup(element, context)
|
|
13
13
|
element.children.each do |child|
|
|
14
|
-
Postsvg::Translation::PsRenderer::DEFAULT_REGISTRY.translate(child,
|
|
15
|
-
context)
|
|
14
|
+
Postsvg::Translation::PsRenderer::DEFAULT_REGISTRY.translate(child, context)
|
|
16
15
|
end
|
|
17
16
|
context.emitter.emit(Model::Operators::GraphicsState::Grestore.new)
|
|
18
17
|
end
|
|
@@ -10,10 +10,9 @@ module Postsvg
|
|
|
10
10
|
# Raster image support is tracked in TODO.roadmap/21-images.md.
|
|
11
11
|
# For now, emit a comment so the serialized PS file has a
|
|
12
12
|
# visible marker of the elided content.
|
|
13
|
-
element.href || "(none)"
|
|
13
|
+
href = element.href || "(none)"
|
|
14
14
|
context.emitter.emit(Model::UnknownOperator.new(keyword: "image"))
|
|
15
|
-
expand_bbox(context, element.x, element.y, element.x + element.width,
|
|
16
|
-
element.y + element.height)
|
|
15
|
+
expand_bbox(context, element.x, element.y, element.x + element.width, element.y + element.height)
|
|
17
16
|
end
|
|
18
17
|
end
|
|
19
18
|
end
|
|
@@ -11,12 +11,8 @@ module Postsvg
|
|
|
11
11
|
emit_transform(element, context)
|
|
12
12
|
emit_stroke(element, context)
|
|
13
13
|
context.emitter.emit(Model::Operators::Path::Newpath.new)
|
|
14
|
-
context.emitter.emit(Model::Operators::Path::Moveto.new(
|
|
15
|
-
|
|
16
|
-
))
|
|
17
|
-
context.emitter.emit(Model::Operators::Path::Lineto.new(
|
|
18
|
-
x: element.x2, y: element.y2,
|
|
19
|
-
))
|
|
14
|
+
context.emitter.emit(Model::Operators::Path::Moveto.new(x: element.x1, y: element.y1))
|
|
15
|
+
context.emitter.emit(Model::Operators::Path::Lineto.new(x: element.x2, y: element.y2))
|
|
20
16
|
context.emitter.emit(Model::Operators::Painting::Stroke.new)
|
|
21
17
|
context.emitter.emit(Model::Operators::GraphicsState::Grestore.new)
|
|
22
18
|
expand_bbox(context, element.x1, element.y1, element.x2, element.y2)
|
|
@@ -9,11 +9,10 @@ module Postsvg
|
|
|
9
9
|
# getter, so no capability check is needed.
|
|
10
10
|
def self.call(element, context)
|
|
11
11
|
element.children.each do |child|
|
|
12
|
-
Postsvg::Translation::PsRenderer.default_registry.translate(child,
|
|
13
|
-
context)
|
|
12
|
+
Postsvg::Translation::PsRenderer.default_registry.translate(child, context)
|
|
14
13
|
end
|
|
15
14
|
end
|
|
16
15
|
end
|
|
17
16
|
end
|
|
18
17
|
end
|
|
19
|
-
end
|
|
18
|
+
end
|
|
@@ -22,8 +22,7 @@ module Postsvg
|
|
|
22
22
|
|
|
23
23
|
# Control-point reflection state for smooth curves. +nil+ when
|
|
24
24
|
# the previous command wasn't a smooth-eligible curve.
|
|
25
|
-
SmoothState = Struct.new(:control_x, :control_y, :smoothable,
|
|
26
|
-
keyword_init: true)
|
|
25
|
+
SmoothState = Struct.new(:control_x, :control_y, :smoothable, keyword_init: true)
|
|
27
26
|
|
|
28
27
|
def self.call(element, context)
|
|
29
28
|
context.emitter.emit(Model::Operators::GraphicsState::Gsave.new)
|
|
@@ -31,8 +30,7 @@ module Postsvg
|
|
|
31
30
|
context.emitter.emit(Model::Operators::Path::Newpath.new)
|
|
32
31
|
|
|
33
32
|
state = PathState.new
|
|
34
|
-
smooth = SmoothState.new(control_x: nil, control_y: nil,
|
|
35
|
-
smoothable: false)
|
|
33
|
+
smooth = SmoothState.new(control_x: nil, control_y: nil, smoothable: false)
|
|
36
34
|
element.commands.each do |cmd|
|
|
37
35
|
dispatch_command(cmd, state, smooth, context)
|
|
38
36
|
end
|
|
@@ -76,8 +74,7 @@ module Postsvg
|
|
|
76
74
|
context.emitter.emit(Model::Operators::Path::Moveto.new(x: x, y: y))
|
|
77
75
|
else
|
|
78
76
|
state.move_to_rel(x, y)
|
|
79
|
-
context.emitter.emit(Model::Operators::Path::Rmoveto.new(dx: x,
|
|
80
|
-
dy: y))
|
|
77
|
+
context.emitter.emit(Model::Operators::Path::Rmoveto.new(dx: x, dy: y))
|
|
81
78
|
end
|
|
82
79
|
smooth.smoothable = false
|
|
83
80
|
end
|
|
@@ -89,8 +86,7 @@ module Postsvg
|
|
|
89
86
|
context.emitter.emit(Model::Operators::Path::Lineto.new(x: x, y: y))
|
|
90
87
|
else
|
|
91
88
|
state.line_to_rel(x, y)
|
|
92
|
-
context.emitter.emit(Model::Operators::Path::Rlineto.new(dx: x,
|
|
93
|
-
dy: y))
|
|
89
|
+
context.emitter.emit(Model::Operators::Path::Rlineto.new(dx: x, dy: y))
|
|
94
90
|
end
|
|
95
91
|
end
|
|
96
92
|
|
|
@@ -100,23 +96,18 @@ module Postsvg
|
|
|
100
96
|
if horizontal
|
|
101
97
|
new_x = v
|
|
102
98
|
state.line_to(new_x, state.current_y)
|
|
103
|
-
context.emitter.emit(Model::Operators::Path::Lineto.new(x: new_x,
|
|
104
|
-
y: state.current_y))
|
|
99
|
+
context.emitter.emit(Model::Operators::Path::Lineto.new(x: new_x, y: state.current_y))
|
|
105
100
|
else
|
|
106
101
|
new_y = v
|
|
107
102
|
state.line_to(state.current_x, new_y)
|
|
108
|
-
context.emitter.emit(Model::Operators::Path::Lineto.new(
|
|
109
|
-
x: state.current_x, y: new_y,
|
|
110
|
-
))
|
|
103
|
+
context.emitter.emit(Model::Operators::Path::Lineto.new(x: state.current_x, y: new_y))
|
|
111
104
|
end
|
|
112
105
|
elsif horizontal
|
|
113
106
|
state.line_to_rel(v, 0)
|
|
114
|
-
context.emitter.emit(Model::Operators::Path::Rlineto.new(dx: v,
|
|
115
|
-
dy: 0))
|
|
107
|
+
context.emitter.emit(Model::Operators::Path::Rlineto.new(dx: v, dy: 0))
|
|
116
108
|
else
|
|
117
109
|
state.line_to_rel(0, v)
|
|
118
|
-
context.emitter.emit(Model::Operators::Path::Rlineto.new(dx: 0,
|
|
119
|
-
dy: v))
|
|
110
|
+
context.emitter.emit(Model::Operators::Path::Rlineto.new(dx: 0, dy: v))
|
|
120
111
|
end
|
|
121
112
|
end
|
|
122
113
|
|
|
@@ -125,8 +116,8 @@ module Postsvg
|
|
|
125
116
|
x1, y1, x2, y2, x3, y3 = adapt_curve_args(args, cmd.opcode, state)
|
|
126
117
|
state.curve_to(x3, y3)
|
|
127
118
|
context.emitter.emit(Model::Operators::Path::Curveto.new(
|
|
128
|
-
|
|
129
|
-
|
|
119
|
+
x1: x1, y1: y1, x2: x2, y2: y2, x3: x3, y3: y3,
|
|
120
|
+
))
|
|
130
121
|
smooth.control_x = x2
|
|
131
122
|
smooth.control_y = y2
|
|
132
123
|
smooth.smoothable = true
|
|
@@ -138,15 +129,14 @@ module Postsvg
|
|
|
138
129
|
x1, y1 = reflect_control(smooth, state)
|
|
139
130
|
state.curve_to(x3, y3)
|
|
140
131
|
context.emitter.emit(Model::Operators::Path::Curveto.new(
|
|
141
|
-
|
|
142
|
-
|
|
132
|
+
x1: x1, y1: y1, x2: x2, y2: y2, x3: x3, y3: y3,
|
|
133
|
+
))
|
|
143
134
|
else
|
|
144
135
|
dx1, dy1 = reflect_control_rel(smooth, state)
|
|
145
|
-
state.curve_to_rel(dx2: x2, dy2: y2, dx3: x3, dy3: y3, dx1: dx1,
|
|
146
|
-
dy1: dy1)
|
|
136
|
+
state.curve_to_rel(dx2: x2, dy2: y2, dx3: x3, dy3: y3, dx1: dx1, dy1: dy1)
|
|
147
137
|
context.emitter.emit(Model::Operators::Path::Rcurveto.new(
|
|
148
|
-
|
|
149
|
-
|
|
138
|
+
dx1: dx1, dy1: dy1, dx2: x2, dy2: y2, dx3: x3, dy3: y3,
|
|
139
|
+
))
|
|
150
140
|
x2 = state.current_x - x2
|
|
151
141
|
y2 = state.current_y - y2
|
|
152
142
|
end
|
|
@@ -160,16 +150,15 @@ module Postsvg
|
|
|
160
150
|
qx, qy, x3, y3 = adapt_quadratic_args(args, cmd.opcode, state)
|
|
161
151
|
# Convert quadratic to cubic: c1 = p0 + 2/3*(q-p0),
|
|
162
152
|
# c2 = p3 + 2/3*(q-p3).
|
|
163
|
-
p0x = state.current_x
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
c2y = y3 + ((2.0 / 3.0) * (qy - y3))
|
|
153
|
+
p0x, p0y = state.current_x, state.current_y
|
|
154
|
+
c1x = p0x + (2.0 / 3.0) * (qx - p0x)
|
|
155
|
+
c1y = p0y + (2.0 / 3.0) * (qy - p0y)
|
|
156
|
+
c2x = x3 + (2.0 / 3.0) * (qx - x3)
|
|
157
|
+
c2y = y3 + (2.0 / 3.0) * (qy - y3)
|
|
169
158
|
state.curve_to(x3, y3)
|
|
170
159
|
context.emitter.emit(Model::Operators::Path::Curveto.new(
|
|
171
|
-
|
|
172
|
-
|
|
160
|
+
x1: c1x, y1: c1y, x2: c2x, y2: c2y, x3: x3, y3: y3,
|
|
161
|
+
))
|
|
173
162
|
smooth.control_x = qx
|
|
174
163
|
smooth.control_y = qy
|
|
175
164
|
smooth.smoothable = true
|
|
@@ -179,17 +168,15 @@ module Postsvg
|
|
|
179
168
|
x3, y3 = cmd.args
|
|
180
169
|
qx, qy =
|
|
181
170
|
if smooth.smoothable
|
|
182
|
-
[reflect_x(smooth.control_x, state),
|
|
183
|
-
reflect_y(smooth.control_y, state)]
|
|
171
|
+
[reflect_x(smooth.control_x, state), reflect_y(smooth.control_y, state)]
|
|
184
172
|
else
|
|
185
173
|
[state.current_x, state.current_y]
|
|
186
174
|
end
|
|
187
|
-
p0x = state.current_x
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
c2y = y3 + ((2.0 / 3.0) * (qy - y3))
|
|
175
|
+
p0x, p0y = state.current_x, state.current_y
|
|
176
|
+
c1x = p0x + (2.0 / 3.0) * (qx - p0x)
|
|
177
|
+
c1y = p0y + (2.0 / 3.0) * (qy - p0y)
|
|
178
|
+
c2x = x3 + (2.0 / 3.0) * (qx - x3)
|
|
179
|
+
c2y = y3 + (2.0 / 3.0) * (qy - y3)
|
|
193
180
|
if cmd.opcode == "T"
|
|
194
181
|
state.curve_to(x3, y3)
|
|
195
182
|
else
|
|
@@ -199,8 +186,8 @@ module Postsvg
|
|
|
199
186
|
state.current_y = p0y + y3
|
|
200
187
|
end
|
|
201
188
|
context.emitter.emit(Model::Operators::Path::Curveto.new(
|
|
202
|
-
|
|
203
|
-
|
|
189
|
+
x1: c1x, y1: c1y, x2: c2x, y2: c2y, x3: state.current_x, y3: state.current_y,
|
|
190
|
+
))
|
|
204
191
|
smooth.control_x = qx
|
|
205
192
|
smooth.control_y = qy
|
|
206
193
|
smooth.smoothable = true
|
|
@@ -216,7 +203,7 @@ module Postsvg
|
|
|
216
203
|
x1: state.current_x, y1: state.current_y,
|
|
217
204
|
rx: rx, ry: ry, x_axis_rotation: x_axis_rotation,
|
|
218
205
|
large_arc: large_arc_flag != 0, sweep: sweep_flag != 0,
|
|
219
|
-
x2: x, y2: y
|
|
206
|
+
x2: x, y2: y,
|
|
220
207
|
)
|
|
221
208
|
# Emit arc with center, radius, angle range. For elliptical
|
|
222
209
|
# arcs (rx != ry or non-zero rotation), emit scale/rotate
|
|
@@ -224,19 +211,17 @@ module Postsvg
|
|
|
224
211
|
if x_axis_rotation.abs > 1e-6 || (rx - ry).abs > 1e-6
|
|
225
212
|
context.emitter.emit(Model::Operators::GraphicsState::Gsave.new)
|
|
226
213
|
context.emitter.emit(Model::Operators::Transformations::Concat.new(matrix: [
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
context.emitter.emit(Model::Operators::Transformations::Scale.new(
|
|
230
|
-
sx: normalized_rx, sy: normalized_ry,
|
|
231
|
-
))
|
|
214
|
+
Math.cos(psi), Math.sin(psi), -Math.sin(psi), Math.cos(psi), cx, cy,
|
|
215
|
+
]))
|
|
216
|
+
context.emitter.emit(Model::Operators::Transformations::Scale.new(sx: normalized_rx, sy: normalized_ry))
|
|
232
217
|
context.emitter.emit(Model::Operators::Path::Arc.new(
|
|
233
|
-
|
|
234
|
-
|
|
218
|
+
x: 0, y: 0, radius: 1.0, angle1: theta1, angle2: theta2,
|
|
219
|
+
))
|
|
235
220
|
context.emitter.emit(Model::Operators::GraphicsState::Grestore.new)
|
|
236
221
|
else
|
|
237
222
|
context.emitter.emit(Model::Operators::Path::Arc.new(
|
|
238
|
-
|
|
239
|
-
|
|
223
|
+
x: cx, y: cy, radius: normalized_rx, angle1: theta1, angle2: theta2,
|
|
224
|
+
))
|
|
240
225
|
end
|
|
241
226
|
state.move_to(x, y)
|
|
242
227
|
end
|
|
@@ -269,8 +254,7 @@ module Postsvg
|
|
|
269
254
|
def self.reflect_control(smooth, state)
|
|
270
255
|
return [state.current_x, state.current_y] unless smooth.smoothable
|
|
271
256
|
|
|
272
|
-
[reflect_x(smooth.control_x, state),
|
|
273
|
-
reflect_y(smooth.control_y, state)]
|
|
257
|
+
[reflect_x(smooth.control_x, state), reflect_y(smooth.control_y, state)]
|
|
274
258
|
end
|
|
275
259
|
|
|
276
260
|
def self.reflect_control_rel(smooth, state)
|
|
@@ -279,11 +263,11 @@ module Postsvg
|
|
|
279
263
|
end
|
|
280
264
|
|
|
281
265
|
def self.reflect_x(control_x, state)
|
|
282
|
-
|
|
266
|
+
2 * state.current_x - control_x
|
|
283
267
|
end
|
|
284
268
|
|
|
285
269
|
def self.reflect_y(control_y, state)
|
|
286
|
-
|
|
270
|
+
2 * state.current_y - control_y
|
|
287
271
|
end
|
|
288
272
|
|
|
289
273
|
# Mutable path-tracking state shared across command handlers.
|
|
@@ -15,11 +15,9 @@ module Postsvg
|
|
|
15
15
|
points = element.points
|
|
16
16
|
points.each_slice(2).with_index do |(x, y), idx|
|
|
17
17
|
if idx.zero?
|
|
18
|
-
context.emitter.emit(Model::Operators::Path::Moveto.new(x: x,
|
|
19
|
-
y: y))
|
|
18
|
+
context.emitter.emit(Model::Operators::Path::Moveto.new(x: x, y: y))
|
|
20
19
|
else
|
|
21
|
-
context.emitter.emit(Model::Operators::Path::Lineto.new(x: x,
|
|
22
|
-
y: y))
|
|
20
|
+
context.emitter.emit(Model::Operators::Path::Lineto.new(x: x, y: y))
|
|
23
21
|
end
|
|
24
22
|
end
|
|
25
23
|
context.emitter.emit(Model::Operators::Path::Closepath.new)
|
|
@@ -14,11 +14,9 @@ module Postsvg
|
|
|
14
14
|
points = element.points
|
|
15
15
|
points.each_slice(2).with_index do |(x, y), idx|
|
|
16
16
|
if idx.zero?
|
|
17
|
-
context.emitter.emit(Model::Operators::Path::Moveto.new(x: x,
|
|
18
|
-
y: y))
|
|
17
|
+
context.emitter.emit(Model::Operators::Path::Moveto.new(x: x, y: y))
|
|
19
18
|
else
|
|
20
|
-
context.emitter.emit(Model::Operators::Path::Lineto.new(x: x,
|
|
21
|
-
y: y))
|
|
19
|
+
context.emitter.emit(Model::Operators::Path::Lineto.new(x: x, y: y))
|
|
22
20
|
end
|
|
23
21
|
end
|
|
24
22
|
context.emitter.emit(Model::Operators::Painting::Stroke.new)
|
|
@@ -10,17 +10,12 @@ module Postsvg
|
|
|
10
10
|
context.emitter.emit(Model::Operators::GraphicsState::Gsave.new)
|
|
11
11
|
emit_transform(element, context)
|
|
12
12
|
context.emitter.emit(Model::Operators::Path::Newpath.new)
|
|
13
|
-
x = element.x
|
|
14
|
-
|
|
15
|
-
w = element.width
|
|
16
|
-
h = element.height
|
|
13
|
+
x, y = element.x, element.y
|
|
14
|
+
w, h = element.width, element.height
|
|
17
15
|
context.emitter.emit(Model::Operators::Path::Moveto.new(x: x, y: y))
|
|
18
|
-
context.emitter.emit(Model::Operators::Path::Rlineto.new(dx: w,
|
|
19
|
-
|
|
20
|
-
context.emitter.emit(Model::Operators::Path::Rlineto.new(dx: 0
|
|
21
|
-
dy: h))
|
|
22
|
-
context.emitter.emit(Model::Operators::Path::Rlineto.new(dx: -w,
|
|
23
|
-
dy: 0))
|
|
16
|
+
context.emitter.emit(Model::Operators::Path::Rlineto.new(dx: w, dy: 0))
|
|
17
|
+
context.emitter.emit(Model::Operators::Path::Rlineto.new(dx: 0, dy: h))
|
|
18
|
+
context.emitter.emit(Model::Operators::Path::Rlineto.new(dx: -w, dy: 0))
|
|
24
19
|
context.emitter.emit(Model::Operators::Path::Closepath.new)
|
|
25
20
|
emit_paint(element, context)
|
|
26
21
|
context.emitter.emit(Model::Operators::GraphicsState::Grestore.new)
|
|
@@ -20,8 +20,8 @@ module Postsvg
|
|
|
20
20
|
def emit_paint(element, context)
|
|
21
21
|
fill_paint = element.fill
|
|
22
22
|
stroke_paint = element.stroke_paint
|
|
23
|
-
fill_on = fill_paint
|
|
24
|
-
stroke_on = stroke_paint
|
|
23
|
+
fill_on = fill_paint && fill_paint.color?
|
|
24
|
+
stroke_on = stroke_paint && stroke_paint.color?
|
|
25
25
|
|
|
26
26
|
if fill_on && stroke_on
|
|
27
27
|
emit_fill(element, context)
|
|
@@ -52,26 +52,26 @@ module Postsvg
|
|
|
52
52
|
|
|
53
53
|
def emit_fill(element, context)
|
|
54
54
|
paint = element.fill
|
|
55
|
-
return unless paint
|
|
55
|
+
return unless paint && paint.color?
|
|
56
56
|
|
|
57
57
|
color = paint.value
|
|
58
58
|
if color.gray?
|
|
59
59
|
context.emitter.emit(Model::Operators::Color::Setgray.new(gray: color.gray_level))
|
|
60
60
|
else
|
|
61
61
|
context.emitter.emit(Model::Operators::Color::Setrgbcolor.new(
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
red: color.red / 255.0, green: color.green / 255.0, blue: color.blue / 255.0,
|
|
63
|
+
))
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def emit_stroke(element, context)
|
|
68
68
|
paint = element.stroke_paint
|
|
69
|
-
return unless paint
|
|
69
|
+
return unless paint && paint.color?
|
|
70
70
|
|
|
71
71
|
color = paint.value
|
|
72
72
|
context.emitter.emit(Model::Operators::Color::Setrgbcolor.new(
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
red: color.red / 255.0, green: color.green / 255.0, blue: color.blue / 255.0,
|
|
74
|
+
))
|
|
75
75
|
stroke = element.stroke
|
|
76
76
|
return unless stroke
|
|
77
77
|
|
|
@@ -92,8 +92,8 @@ module Postsvg
|
|
|
92
92
|
|
|
93
93
|
transform.matrices.each do |matrix|
|
|
94
94
|
context.emitter.emit(Model::Operators::Transformations::Concat.new(matrix: [
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f,
|
|
96
|
+
]))
|
|
97
97
|
end
|
|
98
98
|
end
|
|
99
99
|
|
|
@@ -102,7 +102,7 @@ module Postsvg
|
|
|
102
102
|
ys = points.each_slice(2).map(&:last)
|
|
103
103
|
return if xs.empty?
|
|
104
104
|
|
|
105
|
-
context.expand_bbox!(xs.min..xs.max, ys.min..ys.max)
|
|
105
|
+
context.expand_bbox!((xs.min..xs.max), (ys.min..ys.max))
|
|
106
106
|
end
|
|
107
107
|
end
|
|
108
108
|
end
|
|
@@ -16,11 +16,10 @@ module Postsvg
|
|
|
16
16
|
# Element base class guarantees the +children+ getter.
|
|
17
17
|
def self.descend(element, context)
|
|
18
18
|
element.children.each do |child|
|
|
19
|
-
Postsvg::Translation::PsRenderer.default_registry.translate(child,
|
|
20
|
-
context)
|
|
19
|
+
Postsvg::Translation::PsRenderer.default_registry.translate(child, context)
|
|
21
20
|
end
|
|
22
21
|
end
|
|
23
22
|
end
|
|
24
23
|
end
|
|
25
24
|
end
|
|
26
|
-
end
|
|
25
|
+
end
|
|
@@ -21,19 +21,18 @@ module Postsvg
|
|
|
21
21
|
def self.call(element, context)
|
|
22
22
|
context.emitter.emit(Model::Operators::GraphicsState::Gsave.new)
|
|
23
23
|
emit_transform(element, context)
|
|
24
|
-
emit_fill(element, context) if element.fill
|
|
24
|
+
emit_fill(element, context) if element.fill && element.fill.color?
|
|
25
25
|
|
|
26
26
|
font_name = font_name_value(element)
|
|
27
27
|
context.emitter.emit(Model::Operators::Font::Findfont.new(name: font_name))
|
|
28
28
|
context.emitter.emit(Model::Operators::Font::Scalefont.new(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
font: Model::Computed.new(operator_keyword: "findfont"),
|
|
30
|
+
size: element.font_size,
|
|
31
|
+
))
|
|
32
32
|
context.emitter.emit(Model::Operators::Font::Setfont.new(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
context.emitter.emit(Model::Operators::Path::Moveto.new(x: element.x,
|
|
36
|
-
y: element.y))
|
|
33
|
+
font: Model::Computed.new(operator_keyword: "scalefont"),
|
|
34
|
+
))
|
|
35
|
+
context.emitter.emit(Model::Operators::Path::Moveto.new(x: element.x, y: element.y))
|
|
37
36
|
context.emitter.emit(Model::Operators::Font::Show.new(text: element.content.to_s))
|
|
38
37
|
|
|
39
38
|
context.emitter.emit(Model::Operators::GraphicsState::Grestore.new)
|
|
@@ -17,8 +17,7 @@ module Postsvg
|
|
|
17
17
|
autoload :TextHandler, "postsvg/translation/handlers/text_handler"
|
|
18
18
|
autoload :ImageHandler, "postsvg/translation/handlers/image_handler"
|
|
19
19
|
autoload :DefsHandler, "postsvg/translation/handlers/defs_handler"
|
|
20
|
-
autoload :ClipPathHandler,
|
|
21
|
-
"postsvg/translation/handlers/clip_path_handler"
|
|
20
|
+
autoload :ClipPathHandler, "postsvg/translation/handlers/clip_path_handler"
|
|
22
21
|
autoload :OpenHandler, "postsvg/translation/handlers/open_handler"
|
|
23
22
|
autoload :Shared, "postsvg/translation/handlers/shared"
|
|
24
23
|
end
|
|
@@ -75,8 +75,7 @@ module Postsvg
|
|
|
75
75
|
llx, lly, urx, ury = document.viewbox
|
|
76
76
|
BoundingBox.new(min_x: llx, min_y: lly, max_x: urx, max_y: ury)
|
|
77
77
|
elsif document.width && document.height
|
|
78
|
-
BoundingBox.new(min_x: 0, min_y: 0, max_x: document.width,
|
|
79
|
-
max_y: document.height)
|
|
78
|
+
BoundingBox.new(min_x: 0, min_y: 0, max_x: document.width, max_y: document.height)
|
|
80
79
|
else
|
|
81
80
|
BoundingBox.empty
|
|
82
81
|
end
|
data/lib/postsvg/version.rb
CHANGED
|
@@ -12,19 +12,19 @@ module Postsvg
|
|
|
12
12
|
def visit_add(_op, _ctx)
|
|
13
13
|
b = pop_runtime_number
|
|
14
14
|
a = pop_runtime_number
|
|
15
|
-
@stack <<
|
|
15
|
+
@stack << a + b
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def visit_sub(_op, _ctx)
|
|
19
19
|
b = pop_runtime_number
|
|
20
20
|
a = pop_runtime_number
|
|
21
|
-
@stack <<
|
|
21
|
+
@stack << a - b
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def visit_mul(_op, _ctx)
|
|
25
25
|
b = pop_runtime_number
|
|
26
26
|
a = pop_runtime_number
|
|
27
|
-
@stack <<
|
|
27
|
+
@stack << a * b
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def visit_div(_op, _ctx)
|
|
@@ -32,7 +32,7 @@ module Postsvg
|
|
|
32
32
|
a = pop_runtime_number
|
|
33
33
|
raise RenderError, "division by zero" if divisor.zero?
|
|
34
34
|
|
|
35
|
-
@stack << (a.to_f / divisor)
|
|
35
|
+
@stack << (a.to_f / divisor.to_f)
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def visit_idiv(_op, _ctx)
|
|
@@ -85,7 +85,7 @@ module Postsvg
|
|
|
85
85
|
def visit_atan(_op, _ctx)
|
|
86
86
|
b = pop_runtime_number
|
|
87
87
|
a = pop_runtime_number
|
|
88
|
-
@stack <<
|
|
88
|
+
@stack << Math.atan2(a.to_f, b.to_f) * (180.0 / Math::PI)
|
|
89
89
|
end
|
|
90
90
|
|
|
91
91
|
def visit_cos(_op, _ctx)
|
|
@@ -107,7 +107,7 @@ module Postsvg
|
|
|
107
107
|
def visit_exp(_op, _ctx)
|
|
108
108
|
b = pop_runtime_number
|
|
109
109
|
a = pop_runtime_number
|
|
110
|
-
@stack <<
|
|
110
|
+
@stack << a.to_f**b.to_f
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
private
|
|
@@ -7,25 +7,22 @@ module Postsvg
|
|
|
7
7
|
# GraphicsContext; the next paint operator reads the new colors.
|
|
8
8
|
module Color
|
|
9
9
|
def visit_setgray(op, _ctx)
|
|
10
|
-
color =
|
|
10
|
+
color = Postsvg::Color.gray(op.gray.to_f)
|
|
11
11
|
@graphics.update(fill_color: color, stroke_color: color)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def visit_setrgbcolor(op, _ctx)
|
|
15
|
-
color =
|
|
16
|
-
op.blue.to_f)
|
|
15
|
+
color = Postsvg::Color.rgb(op.red.to_f, op.green.to_f, op.blue.to_f)
|
|
17
16
|
@graphics.update(fill_color: color, stroke_color: color)
|
|
18
17
|
end
|
|
19
18
|
|
|
20
19
|
def visit_setcmykcolor(op, _ctx)
|
|
21
|
-
color =
|
|
22
|
-
op.yellow.to_f, op.key.to_f)
|
|
20
|
+
color = Postsvg::Color.cmyk(op.cyan.to_f, op.magenta.to_f, op.yellow.to_f, op.key.to_f)
|
|
23
21
|
@graphics.update(fill_color: color, stroke_color: color)
|
|
24
22
|
end
|
|
25
23
|
|
|
26
24
|
def visit_sethsbcolor(op, _ctx)
|
|
27
|
-
color = hsb_to_color(op.hue.to_f, op.saturation.to_f,
|
|
28
|
-
op.brightness.to_f)
|
|
25
|
+
color = hsb_to_color(op.hue.to_f, op.saturation.to_f, op.brightness.to_f)
|
|
29
26
|
@graphics.update(fill_color: color, stroke_color: color)
|
|
30
27
|
end
|
|
31
28
|
|
|
@@ -48,7 +45,7 @@ module Postsvg
|
|
|
48
45
|
when 4 then [t, p, v]
|
|
49
46
|
else [v, p, q]
|
|
50
47
|
end
|
|
51
|
-
|
|
48
|
+
Postsvg::Color.rgb(r, g, b)
|
|
52
49
|
end
|
|
53
50
|
end
|
|
54
51
|
end
|
|
@@ -13,7 +13,7 @@ module Postsvg
|
|
|
13
13
|
def normalize_key(key)
|
|
14
14
|
case key
|
|
15
15
|
when Model::Literals::Name then key.value
|
|
16
|
-
when String then key.to_s.
|
|
16
|
+
when String then key.to_s.sub(/\A\//, "")
|
|
17
17
|
else key.to_s
|
|
18
18
|
end
|
|
19
19
|
end
|
|
@@ -25,6 +25,7 @@ module Postsvg
|
|
|
25
25
|
when String then node
|
|
26
26
|
when Model::Literals::StringLiteral then node.value
|
|
27
27
|
when Model::Literals::HexLiteral then node.bytes
|
|
28
|
+
else nil
|
|
28
29
|
end
|
|
29
30
|
end
|
|
30
31
|
|
|
@@ -44,25 +44,25 @@ module Postsvg
|
|
|
44
44
|
@stack << value
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
def visit_put(
|
|
47
|
+
def visit_put(op, _ctx)
|
|
48
48
|
# PS put mutates in place. Our value objects are immutable.
|
|
49
49
|
# Marked as a comment in the output so the gap is visible.
|
|
50
50
|
@builder.comment("put: in-place mutation not supported")
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
def visit_getinterval(op, _ctx)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
54
|
+
case op.operand
|
|
55
|
+
when String
|
|
56
|
+
@stack << op.operand[op.start, op.count]
|
|
57
|
+
when Array
|
|
58
|
+
@stack << op.operand[op.start, op.count]
|
|
59
|
+
when Model::Literals::StringLiteral
|
|
60
|
+
@stack << op.operand.value[op.start, op.count]
|
|
61
|
+
when Model::Literals::ArrayLiteral
|
|
62
|
+
@stack << op.operand.elements[op.start, op.count]
|
|
63
|
+
else
|
|
64
|
+
@stack << ""
|
|
65
|
+
end
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
def visit_putinterval(_op, _ctx)
|
|
@@ -39,7 +39,7 @@ module Postsvg
|
|
|
39
39
|
body = @stack.pop
|
|
40
40
|
LOOP_LIMIT.times do
|
|
41
41
|
descend_into_procedure(body)
|
|
42
|
-
rescue
|
|
42
|
+
rescue Postsvg::ExitSignal
|
|
43
43
|
break
|
|
44
44
|
end
|
|
45
45
|
end
|
|
@@ -74,11 +74,11 @@ module Postsvg
|
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
def visit_exit(_op, _ctx)
|
|
77
|
-
raise
|
|
77
|
+
raise Postsvg::ExitSignal
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
def visit_quit(_op, _ctx)
|
|
81
|
-
raise
|
|
81
|
+
raise Postsvg::QuitSignal
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
def visit_exec(_op, _ctx)
|