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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +49 -533
  3. data/Gemfile +1 -1
  4. data/lib/postsvg/cli.rb +5 -10
  5. data/lib/postsvg/color.rb +132 -0
  6. data/lib/postsvg/format_number.rb +22 -0
  7. data/lib/postsvg/graphics_context.rb +1 -2
  8. data/lib/postsvg/matrix.rb +106 -0
  9. data/lib/postsvg/model/literals/array.rb +41 -0
  10. data/lib/postsvg/model/literals/dictionary.rb +34 -0
  11. data/lib/postsvg/model/literals/hex.rb +37 -0
  12. data/lib/postsvg/model/literals/name.rb +40 -0
  13. data/lib/postsvg/model/literals/number.rb +36 -0
  14. data/lib/postsvg/model/literals/procedure.rb +41 -0
  15. data/lib/postsvg/model/literals/string.rb +30 -0
  16. data/lib/postsvg/model/literals.rb +19 -0
  17. data/lib/postsvg/model/operator.rb +58 -0
  18. data/lib/postsvg/model/operators/arithmetic.rb +264 -0
  19. data/lib/postsvg/model/operators/boolean.rb +182 -0
  20. data/lib/postsvg/model/operators/color.rb +74 -0
  21. data/lib/postsvg/model/operators/container.rb +186 -0
  22. data/lib/postsvg/model/operators/control_flow.rb +119 -0
  23. data/lib/postsvg/model/operators/device.rb +21 -0
  24. data/lib/postsvg/model/operators/dictionary.rb +118 -0
  25. data/lib/postsvg/model/operators/font.rb +121 -0
  26. data/lib/postsvg/model/operators/graphics_state.rb +84 -0
  27. data/lib/postsvg/model/operators/painting.rb +29 -0
  28. data/lib/postsvg/model/operators/path.rb +169 -0
  29. data/lib/postsvg/model/operators/stack.rb +72 -0
  30. data/lib/postsvg/model/operators/transformations.rb +103 -0
  31. data/lib/postsvg/model/operators.rb +89 -0
  32. data/lib/postsvg/model/program.rb +68 -0
  33. data/lib/postsvg/model/token.rb +43 -0
  34. data/lib/postsvg/model.rb +17 -0
  35. data/lib/postsvg/options.rb +1 -1
  36. data/lib/postsvg/parser/postscript_parser.rb +7 -7
  37. data/lib/postsvg/renderer.rb +3 -7
  38. data/lib/postsvg/serializer.rb +325 -0
  39. data/lib/postsvg/source/ast_builder.rb +308 -0
  40. data/lib/postsvg/source/lexer.rb +322 -0
  41. data/lib/postsvg/source/operand_stack.rb +55 -0
  42. data/lib/postsvg/source.rb +21 -0
  43. data/lib/postsvg/svg/clip_path_registry.rb +1 -3
  44. data/lib/postsvg/svg/element.rb +1 -3
  45. data/lib/postsvg/svg/elements/ellipse.rb +1 -2
  46. data/lib/postsvg/svg/elements/svg.rb +1 -2
  47. data/lib/postsvg/svg/paint.rb +1 -1
  48. data/lib/postsvg/svg/path_data/parser.rb +6 -10
  49. data/lib/postsvg/svg/stroke.rb +2 -4
  50. data/lib/postsvg/svg/transform_list.rb +1 -1
  51. data/lib/postsvg/svg_builder.rb +11 -15
  52. data/lib/postsvg/translation/arc_converter.rb +12 -22
  53. data/lib/postsvg/translation/bounding_box.rb +4 -7
  54. data/lib/postsvg/translation/handlers/circle_handler.rb +2 -2
  55. data/lib/postsvg/translation/handlers/ellipse_handler.rb +3 -8
  56. data/lib/postsvg/translation/handlers/group_handler.rb +1 -2
  57. data/lib/postsvg/translation/handlers/image_handler.rb +2 -3
  58. data/lib/postsvg/translation/handlers/line_handler.rb +2 -6
  59. data/lib/postsvg/translation/handlers/open_handler.rb +2 -3
  60. data/lib/postsvg/translation/handlers/path_handler.rb +41 -57
  61. data/lib/postsvg/translation/handlers/polygon_handler.rb +2 -4
  62. data/lib/postsvg/translation/handlers/polyline_handler.rb +2 -4
  63. data/lib/postsvg/translation/handlers/rect_handler.rb +5 -10
  64. data/lib/postsvg/translation/handlers/shared.rb +11 -11
  65. data/lib/postsvg/translation/handlers/svg_handler.rb +2 -3
  66. data/lib/postsvg/translation/handlers/text_handler.rb +7 -8
  67. data/lib/postsvg/translation/handlers.rb +1 -2
  68. data/lib/postsvg/translation/ps_renderer.rb +1 -2
  69. data/lib/postsvg/version.rb +1 -1
  70. data/lib/postsvg/visitors/ps_visitor/arithmetic.rb +6 -6
  71. data/lib/postsvg/visitors/ps_visitor/color.rb +5 -8
  72. data/lib/postsvg/visitors/ps_visitor/common.rb +2 -1
  73. data/lib/postsvg/visitors/ps_visitor/container.rb +13 -13
  74. data/lib/postsvg/visitors/ps_visitor/control_flow.rb +3 -3
  75. data/lib/postsvg/visitors/ps_visitor/dictionary.rb +4 -8
  76. data/lib/postsvg/visitors/ps_visitor/font.rb +4 -14
  77. data/lib/postsvg/visitors/ps_visitor/graphics_state.rb +4 -4
  78. data/lib/postsvg/visitors/ps_visitor/painting.rb +1 -1
  79. data/lib/postsvg/visitors/ps_visitor/path.rb +4 -9
  80. data/lib/postsvg.rb +37 -42
  81. 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
- tx: cx, ty: cy,
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
- x: element.x1, y: element.y1,
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
- x1: x1, y1: y1, x2: x2, y2: y2, x3: x3, y3: y3,
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
- x1: x1, y1: y1, x2: x2, y2: y2, x3: x3, y3: y3,
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
- dx1: dx1, dy1: dy1, dx2: x2, dy2: y2, dx3: x3, dy3: y3,
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
- p0y = state.current_y
165
- c1x = p0x + ((2.0 / 3.0) * (qx - p0x))
166
- c1y = p0y + ((2.0 / 3.0) * (qy - p0y))
167
- c2x = x3 + ((2.0 / 3.0) * (qx - x3))
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
- x1: c1x, y1: c1y, x2: c2x, y2: c2y, x3: x3, y3: y3,
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
- p0y = state.current_y
189
- c1x = p0x + ((2.0 / 3.0) * (qx - p0x))
190
- c1y = p0y + ((2.0 / 3.0) * (qy - p0y))
191
- c2x = x3 + ((2.0 / 3.0) * (qx - x3))
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
- x1: c1x, y1: c1y, x2: c2x, y2: c2y, x3: state.current_x, y3: state.current_y,
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
- Math.cos(psi), Math.sin(psi), -Math.sin(psi), Math.cos(psi), cx, cy
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
- x: 0, y: 0, radius: 1.0, angle1: theta1, angle2: theta2,
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
- x: cx, y: cy, radius: normalized_rx, angle1: theta1, angle2: theta2,
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
- (2 * state.current_x) - control_x
266
+ 2 * state.current_x - control_x
283
267
  end
284
268
 
285
269
  def self.reflect_y(control_y, state)
286
- (2 * state.current_y) - control_y
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
- y = element.y
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
- dy: 0))
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&.color?
24
- stroke_on = stroke_paint&.color?
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&.color?
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
- red: color.red / 255.0, green: color.green / 255.0, blue: color.blue / 255.0,
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&.color?
69
+ return unless paint && paint.color?
70
70
 
71
71
  color = paint.value
72
72
  context.emitter.emit(Model::Operators::Color::Setrgbcolor.new(
73
- red: color.red / 255.0, green: color.green / 255.0, blue: color.blue / 255.0,
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
- matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f
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&.color?
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
- font: Model::Computed.new(operator_keyword: "findfont"),
30
- size: element.font_size,
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
- font: Model::Computed.new(operator_keyword: "scalefont"),
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Postsvg
4
- VERSION = "0.2.2"
4
+ VERSION = "0.3.0"
5
5
  end
@@ -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 << (a + b)
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 << (a - b)
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 << (a * b)
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 << (Math.atan2(a.to_f, b.to_f) * (180.0 / Math::PI))
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 << (a.to_f**b.to_f)
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 = Postscript::Color.gray(op.gray.to_f)
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 = Postscript::Color.rgb(op.red.to_f, op.green.to_f,
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 = Postscript::Color.cmyk(op.cyan.to_f, op.magenta.to_f,
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
- Postscript::Color.rgb(r, g, b)
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.delete_prefix("/")
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(_op, _ctx)
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
- @stack << case op.operand
55
- when String
56
- op.operand[op.start, op.count]
57
- when Array
58
- op.operand[op.start, op.count]
59
- when Model::Literals::StringLiteral
60
- op.operand.value[op.start, op.count]
61
- when Model::Literals::ArrayLiteral
62
- op.operand.elements[op.start, op.count]
63
- else
64
- ""
65
- end
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 Postscript::ExitSignal
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 Postscript::ExitSignal
77
+ raise Postsvg::ExitSignal
78
78
  end
79
79
 
80
80
  def visit_quit(_op, _ctx)
81
- raise Postscript::QuitSignal
81
+ raise Postsvg::QuitSignal
82
82
  end
83
83
 
84
84
  def visit_exec(_op, _ctx)