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
@@ -72,14 +72,10 @@ module Postsvg
72
72
 
73
73
  def visit_maxlength(op, _ctx)
74
74
  # PS dictionaries can grow dynamically; report current size.
75
- @stack << dict_size(op.operand)
76
- end
77
-
78
- def dict_size(operand)
79
- case operand
80
- when Hash then operand.length
81
- when Model::Literals::Dictionary then operand.entries.length
82
- else 0
75
+ case op.operand
76
+ when Hash then @stack << op.operand.length
77
+ when Model::Literals::Dictionary then @stack << op.operand.entries.length
78
+ else @stack << 0
83
79
  end
84
80
  end
85
81
 
@@ -31,25 +31,15 @@ module Postsvg
31
31
  end
32
32
 
33
33
  def visit_scalefont(op, _ctx)
34
- size = op.size.to_i
34
+ size = op.size.to_i || op.size.to_f
35
35
  font = @stack.pop
36
- base = if font.is_a?(FontRef)
37
- font
38
- else
39
- FontRef.new(name: "Helvetica",
40
- size: nil)
41
- end
36
+ base = font.is_a?(FontRef) ? font : FontRef.new(name: "Helvetica", size: nil)
42
37
  @stack << FontRef.new(name: base.name, size: size.to_f)
43
38
  end
44
39
 
45
40
  def visit_setfont(_op, _ctx)
46
41
  font = @stack.pop
47
- ref = if font.is_a?(FontRef)
48
- font
49
- else
50
- FontRef.new(name: "Helvetica",
51
- size: 12.0)
52
- end
42
+ ref = font.is_a?(FontRef) ? font : FontRef.new(name: "Helvetica", size: 12.0)
53
43
  @graphics.update(font_name: ref.name || "Helvetica",
54
44
  font_size: ref.size || 12.0)
55
45
  end
@@ -77,7 +67,7 @@ module Postsvg
77
67
  y: -screen_pos[:y],
78
68
  font_family: @graphics.current.font_name,
79
69
  font_size: @graphics.current.font_size,
80
- color: color || Postscript::Color::BLACK,
70
+ color: color || Postsvg::Color::BLACK,
81
71
  transform: "scale(1 -1)",
82
72
  )
83
73
  @path.reset
@@ -23,14 +23,12 @@ module Postsvg
23
23
  end
24
24
 
25
25
  def visit_setlinecap(op, _ctx)
26
- name = { 0 => :butt, 1 => :round, 2 => :square }.fetch(op.cap_code,
27
- :butt)
26
+ name = { 0 => :butt, 1 => :round, 2 => :square }.fetch(op.cap_code, :butt)
28
27
  @graphics.update(line_cap: name)
29
28
  end
30
29
 
31
30
  def visit_setlinejoin(op, _ctx)
32
- name = { 0 => :miter, 1 => :round, 2 => :bevel }.fetch(op.join_code,
33
- :miter)
31
+ name = { 0 => :miter, 1 => :round, 2 => :bevel }.fetch(op.join_code, :miter)
34
32
  @graphics.update(line_join: name)
35
33
  end
36
34
 
@@ -46,6 +44,8 @@ module Postsvg
46
44
  pattern.map { |v| FormatNumber.call(v.to_f) }.join(" ")
47
45
  when Numeric
48
46
  FormatNumber.call(pattern.to_f)
47
+ else
48
+ nil
49
49
  end
50
50
  @graphics.update(dash: dash_str)
51
51
  end
@@ -66,7 +66,7 @@ module Postsvg
66
66
  line_cap: ctx.line_cap,
67
67
  line_join: ctx.line_join,
68
68
  dash: ctx.dash,
69
- clip_path_id: clip_path_id
69
+ clip_path_id: clip_path_id,
70
70
  )
71
71
  end
72
72
 
@@ -23,8 +23,7 @@ module Postsvg
23
23
  pos = @graphics.current.last_text_position
24
24
  base_x = pos ? pos[:x] : 0
25
25
  base_y = pos ? pos[:y] : 0
26
- @graphics.update(last_text_position: { x: base_x + op.dx,
27
- y: base_y + op.dy })
26
+ @graphics.update(last_text_position: { x: base_x + op.dx, y: base_y + op.dy })
28
27
  end
29
28
 
30
29
  def visit_lineto(op, _ctx)
@@ -78,8 +77,8 @@ module Postsvg
78
77
 
79
78
  # If the current path is empty, the arc implicitly starts
80
79
  # with a moveto to its starting point.
81
- if (@path.empty? || last_command_starts_with?("M")) && @path.empty?
82
- @path.move_to(start_x, start_y)
80
+ if @path.empty? || last_command_starts_with?("M")
81
+ @path.move_to(start_x, start_y) if @path.empty?
83
82
  end
84
83
 
85
84
  delta = (angle2 - angle1) % 360
@@ -87,11 +86,7 @@ module Postsvg
87
86
  large_arc = delta > 180
88
87
 
89
88
  # SVG sweep flag is 1 when the arc is drawn clockwise.
90
- svg_sweep = if sweep
91
- delta.positive? ? 1 : 0
92
- else
93
- 0
94
- end
89
+ svg_sweep = sweep ? (delta.positive? ? 1 : 0) : 0
95
90
  if delta.abs < 1e-6
96
91
  # Full circle: emit two arcs.
97
92
  mid_angle = angle1 + 180
data/lib/postsvg.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "postscript"
4
3
  require "parslet"
5
4
  require "thor"
6
5
  require "nokogiri"
@@ -8,61 +7,57 @@ require "nokogiri"
8
7
  module Postsvg
9
8
  autoload :VERSION, "postsvg/version"
10
9
 
11
- # ============================================================
12
- # Posts created and managed by the +postscript+ gem.
13
- # ============================================================
14
- #
15
- # `postscript` owns PS source parsing, the typed PS domain model,
16
- # and the PS source serializer. The `Postscript` namespace is the
17
- # canonical location; the aliases below keep existing user code
18
- # working during the transition (deprecated, will be removed at
19
- # postsvg 1.0).
20
- #
21
- # If you maintain postsvg, prefer `Postscript::*` in new code.
22
-
23
- Source = Postscript::Source
24
- Model = Postscript::Model
25
- Serializer = Postscript::Serializer
26
- Matrix = Postscript::Matrix
27
- Color = Postscript::Color
28
- FormatNumber = Postscript::FormatNumber
29
-
30
- ParseError = Postscript::ParseError
31
- LexError = Postscript::LexError
32
- SyntaxError = Postscript::SyntaxError
33
- StackUnderflowError = Postscript::StackUnderflowError
34
- UndefinedOperatorError = Postscript::UndefinedOperatorError
35
- RecursionLimitError = Postscript::RecursionLimitError
36
- RenderError = Postscript::RenderError
37
- SerializeError = Postscript::SerializeError
38
- ExitSignal = Postscript::ExitSignal
39
- QuitSignal = Postscript::QuitSignal
40
-
41
- # ============================================================
42
- # Errors that originate in the SVG side (kept here, not in postscript).
43
- # ============================================================
10
+ # Errors
44
11
  autoload :Error, "postsvg/errors"
12
+ autoload :ParseError, "postsvg/errors"
13
+ autoload :LexError, "postsvg/errors"
14
+ autoload :SyntaxError, "postsvg/errors"
15
+ autoload :RenderError, "postsvg/errors"
16
+ autoload :StackUnderflowError, "postsvg/errors"
17
+ autoload :UndefinedOperatorError, "postsvg/errors"
18
+ autoload :RecursionLimitError, "postsvg/errors"
19
+ autoload :SizeLimitError, "postsvg/errors"
45
20
  autoload :TranslationError, "postsvg/errors"
46
21
  autoload :UnsupportedElementError, "postsvg/errors"
47
22
  autoload :UnresolvedReferenceError, "postsvg/errors"
23
+ autoload :SerializeError, "postsvg/errors"
24
+ autoload :ConversionError, "postsvg/errors"
25
+ autoload :UnsupportedOperatorError, "postsvg/errors"
26
+ autoload :ExitSignal, "postsvg/errors"
27
+ autoload :QuitSignal, "postsvg/errors"
48
28
 
49
- # Legacy alias for RenderError (postsvg 0.1 API).
50
- ConversionError = RenderError
51
- # Legacy alias for UndefinedOperatorError (postsvg 0.1 API).
52
- UnsupportedOperatorError = UndefinedOperatorError
29
+ # Foundational value types
30
+ autoload :FormatNumber, "postsvg/format_number"
31
+ autoload :Matrix, "postsvg/matrix"
32
+ autoload :Color, "postsvg/color"
53
33
 
54
- # ============================================================
55
- # Rendering / SVG-side types owned by postsvg.
56
- # ============================================================
34
+ # Source-reading layer (PS source -> Model::Program)
35
+ autoload :Source, "postsvg/source"
36
+
37
+ # PS domain model
38
+ autoload :Model, "postsvg/model"
39
+
40
+ # Graphics state
57
41
  autoload :GraphicsContext, "postsvg/graphics_context"
58
42
  autoload :GraphicsStack, "postsvg/graphics_stack"
59
43
  autoload :PathBuilder, "postsvg/path_builder"
44
+
45
+ # SVG emission (forward direction)
60
46
  autoload :SvgBuilder, "postsvg/svg_builder"
47
+
48
+ # Forward direction (PS -> SVG)
61
49
  autoload :Options, "postsvg/options"
62
50
  autoload :Renderer, "postsvg/renderer"
63
51
  autoload :Visitors, "postsvg/visitors"
52
+
53
+ # SVG domain model (reverse direction input)
64
54
  autoload :Svg, "postsvg/svg"
55
+
56
+ # Reverse direction (SVG -> PS)
65
57
  autoload :Translation, "postsvg/translation"
58
+ autoload :Serializer, "postsvg/serializer"
59
+
60
+ # CLI
66
61
  autoload :CLI, "postsvg/cli"
67
62
 
68
63
  # Legacy implementations retained on disk for reference. Not on the
@@ -78,7 +73,7 @@ module Postsvg
78
73
  class << self
79
74
  # PS/EPS source -> SVG string.
80
75
  def to_svg(source, **options)
81
- program = Postscript::Source.parse(source)
76
+ program = Source.parse(source)
82
77
  Renderer.call(program, Options.new(**options))
83
78
  end
84
79
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: postsvg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-07-29 00:00:00.000000000 Z
11
+ date: 2026-07-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: postscript
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '0.2'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '0.2'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: thor
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -188,19 +174,53 @@ files:
188
174
  - exe/postsvg
189
175
  - lib/postsvg.rb
190
176
  - lib/postsvg/cli.rb
177
+ - lib/postsvg/color.rb
191
178
  - lib/postsvg/colors.rb
192
179
  - lib/postsvg/converter.rb
193
180
  - lib/postsvg/errors.rb
181
+ - lib/postsvg/format_number.rb
194
182
  - lib/postsvg/graphics_context.rb
195
183
  - lib/postsvg/graphics_stack.rb
196
184
  - lib/postsvg/graphics_state.rb
197
185
  - lib/postsvg/interpreter.rb
186
+ - lib/postsvg/matrix.rb
187
+ - lib/postsvg/model.rb
188
+ - lib/postsvg/model/literals.rb
189
+ - lib/postsvg/model/literals/array.rb
190
+ - lib/postsvg/model/literals/dictionary.rb
191
+ - lib/postsvg/model/literals/hex.rb
192
+ - lib/postsvg/model/literals/name.rb
193
+ - lib/postsvg/model/literals/number.rb
194
+ - lib/postsvg/model/literals/procedure.rb
195
+ - lib/postsvg/model/literals/string.rb
196
+ - lib/postsvg/model/operator.rb
197
+ - lib/postsvg/model/operators.rb
198
+ - lib/postsvg/model/operators/arithmetic.rb
199
+ - lib/postsvg/model/operators/boolean.rb
200
+ - lib/postsvg/model/operators/color.rb
201
+ - lib/postsvg/model/operators/container.rb
202
+ - lib/postsvg/model/operators/control_flow.rb
203
+ - lib/postsvg/model/operators/device.rb
204
+ - lib/postsvg/model/operators/dictionary.rb
205
+ - lib/postsvg/model/operators/font.rb
206
+ - lib/postsvg/model/operators/graphics_state.rb
207
+ - lib/postsvg/model/operators/painting.rb
208
+ - lib/postsvg/model/operators/path.rb
209
+ - lib/postsvg/model/operators/stack.rb
210
+ - lib/postsvg/model/operators/transformations.rb
211
+ - lib/postsvg/model/program.rb
212
+ - lib/postsvg/model/token.rb
198
213
  - lib/postsvg/options.rb
199
214
  - lib/postsvg/parser.rb
200
215
  - lib/postsvg/parser/postscript_parser.rb
201
216
  - lib/postsvg/parser/transform.rb
202
217
  - lib/postsvg/path_builder.rb
203
218
  - lib/postsvg/renderer.rb
219
+ - lib/postsvg/serializer.rb
220
+ - lib/postsvg/source.rb
221
+ - lib/postsvg/source/ast_builder.rb
222
+ - lib/postsvg/source/lexer.rb
223
+ - lib/postsvg/source/operand_stack.rb
204
224
  - lib/postsvg/svg.rb
205
225
  - lib/postsvg/svg/attribute_parser.rb
206
226
  - lib/postsvg/svg/clip_path_registry.rb