postsvg 0.1.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 (41) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +19 -0
  3. data/.rubocop_todo.yml +141 -0
  4. data/Gemfile +15 -0
  5. data/LICENSE +25 -0
  6. data/README.adoc +473 -0
  7. data/Rakefile +10 -0
  8. data/docs/POSTSCRIPT.adoc +13 -0
  9. data/docs/postscript/fundamentals.adoc +356 -0
  10. data/docs/postscript/graphics-model.adoc +406 -0
  11. data/docs/postscript/implementation-notes.adoc +314 -0
  12. data/docs/postscript/index.adoc +153 -0
  13. data/docs/postscript/operators/arithmetic.adoc +461 -0
  14. data/docs/postscript/operators/control-flow.adoc +230 -0
  15. data/docs/postscript/operators/dictionary.adoc +191 -0
  16. data/docs/postscript/operators/graphics-state.adoc +528 -0
  17. data/docs/postscript/operators/index.adoc +288 -0
  18. data/docs/postscript/operators/painting.adoc +475 -0
  19. data/docs/postscript/operators/path-construction.adoc +553 -0
  20. data/docs/postscript/operators/stack-manipulation.adoc +374 -0
  21. data/docs/postscript/operators/transformations.adoc +479 -0
  22. data/docs/postscript/svg-mapping.adoc +369 -0
  23. data/exe/postsvg +6 -0
  24. data/lib/postsvg/cli.rb +103 -0
  25. data/lib/postsvg/colors.rb +33 -0
  26. data/lib/postsvg/converter.rb +214 -0
  27. data/lib/postsvg/errors.rb +11 -0
  28. data/lib/postsvg/graphics_state.rb +158 -0
  29. data/lib/postsvg/interpreter.rb +891 -0
  30. data/lib/postsvg/matrix.rb +106 -0
  31. data/lib/postsvg/parser/postscript_parser.rb +87 -0
  32. data/lib/postsvg/parser/transform.rb +21 -0
  33. data/lib/postsvg/parser.rb +18 -0
  34. data/lib/postsvg/path_builder.rb +101 -0
  35. data/lib/postsvg/svg_generator.rb +78 -0
  36. data/lib/postsvg/tokenizer.rb +161 -0
  37. data/lib/postsvg/version.rb +5 -0
  38. data/lib/postsvg.rb +78 -0
  39. data/postsvg.gemspec +38 -0
  40. data/scripts/regenerate_fixtures.rb +28 -0
  41. metadata +118 -0
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Postsvg
4
+ class Error < StandardError; end
5
+
6
+ class ParseError < Error; end
7
+
8
+ class ConversionError < Error; end
9
+
10
+ class UnsupportedOperatorError < Error; end
11
+ end
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Postsvg
4
+ # Manages PostScript graphics state including path, color, transforms, etc.
5
+ class GraphicsState
6
+ attr_accessor :line_width, :current_x, :current_y
7
+ attr_reader :current_path, :fill_color, :stroke_color
8
+
9
+ def initialize
10
+ @current_path = []
11
+ @current_x = 0
12
+ @current_y = 0
13
+ @line_width = 1.0
14
+ @fill_color = { r: 0, g: 0, b: 0 }
15
+ @stroke_color = { r: 0, g: 0, b: 0 }
16
+ @state_stack = []
17
+ @transform_matrix = [1, 0, 0, 1, 0, 0] # Identity matrix [a, b, c, d, e, f]
18
+ end
19
+
20
+ # Path construction operations
21
+ def moveto(x, y)
22
+ coords = transform_point(x, y)
23
+ @current_x = coords[:x]
24
+ @current_y = coords[:y]
25
+ @current_path << { type: :moveto, x: @current_x, y: @current_y }
26
+ end
27
+
28
+ def lineto(x, y)
29
+ coords = transform_point(x, y)
30
+ @current_x = coords[:x]
31
+ @current_y = coords[:y]
32
+ @current_path << { type: :lineto, x: @current_x, y: @current_y }
33
+ end
34
+
35
+ def rlineto(dx, dy)
36
+ # Relative line to
37
+ lineto(@current_x + dx, @current_y + dy)
38
+ end
39
+
40
+ def curveto(x1, y1, x2, y2, x3, y3)
41
+ coords1 = transform_point(x1, y1)
42
+ coords2 = transform_point(x2, y2)
43
+ coords3 = transform_point(x3, y3)
44
+
45
+ @current_path << {
46
+ type: :curveto,
47
+ x1: coords1[:x], y1: coords1[:y],
48
+ x2: coords2[:x], y2: coords2[:y],
49
+ x3: coords3[:x], y3: coords3[:y]
50
+ }
51
+
52
+ @current_x = coords3[:x]
53
+ @current_y = coords3[:y]
54
+ end
55
+
56
+ def closepath
57
+ @current_path << { type: :closepath }
58
+ end
59
+
60
+ def newpath
61
+ @current_path = []
62
+ end
63
+
64
+ # Color operations
65
+ def set_rgb_color(r, g, b)
66
+ color = { r: r, g: g, b: b }
67
+ @fill_color = color
68
+ @stroke_color = color
69
+ end
70
+
71
+ def set_gray(gray)
72
+ set_rgb_color(gray, gray, gray)
73
+ end
74
+
75
+ # Graphics state stack
76
+ def save
77
+ @state_stack.push({
78
+ path: @current_path.dup,
79
+ x: @current_x,
80
+ y: @current_y,
81
+ line_width: @line_width,
82
+ fill_color: @fill_color.dup,
83
+ stroke_color: @stroke_color.dup,
84
+ transform_matrix: @transform_matrix.dup,
85
+ })
86
+ end
87
+
88
+ def restore
89
+ return if @state_stack.empty?
90
+
91
+ state = @state_stack.pop
92
+ @current_path = state[:path]
93
+ @current_x = state[:x]
94
+ @current_y = state[:y]
95
+ @line_width = state[:line_width]
96
+ @fill_color = state[:fill_color]
97
+ @stroke_color = state[:stroke_color]
98
+ @transform_matrix = state[:transform_matrix]
99
+ end
100
+
101
+ # Transformation operations
102
+ def translate(tx, ty)
103
+ # Modify transformation matrix for translation
104
+ @transform_matrix[4] += tx
105
+ @transform_matrix[5] += ty
106
+ end
107
+
108
+ def scale(sx, sy)
109
+ # Modify transformation matrix for scaling
110
+ @transform_matrix[0] *= sx
111
+ @transform_matrix[1] *= sx
112
+ @transform_matrix[2] *= sy
113
+ @transform_matrix[3] *= sy
114
+ end
115
+
116
+ def rotate(angle)
117
+ # Convert angle from degrees to radians
118
+ rad = angle * Math::PI / 180.0
119
+ cos_a = Math.cos(rad)
120
+ sin_a = Math.sin(rad)
121
+
122
+ # Create rotation matrix and multiply with current matrix
123
+ a, b, c, d, e, f = @transform_matrix
124
+ @transform_matrix = [
125
+ (a * cos_a) + (c * sin_a),
126
+ (b * cos_a) + (d * sin_a),
127
+ (-a * sin_a) + (c * cos_a),
128
+ (-b * sin_a) + (d * cos_a),
129
+ e,
130
+ f,
131
+ ]
132
+ end
133
+
134
+ # Helper methods
135
+ def rgb_to_hex(r, g, b)
136
+ format("#%02x%02x%02x", (r * 255).to_i, (g * 255).to_i, (b * 255).to_i)
137
+ end
138
+
139
+ def fill_color_hex
140
+ rgb_to_hex(fill_color[:r], fill_color[:g], fill_color[:b])
141
+ end
142
+
143
+ def stroke_color_hex
144
+ rgb_to_hex(stroke_color[:r], stroke_color[:g], stroke_color[:b])
145
+ end
146
+
147
+ private
148
+
149
+ def transform_point(x, y)
150
+ # Apply transformation matrix to point
151
+ a, b, c, d, e, f = @transform_matrix
152
+ {
153
+ x: (a * x) + (c * y) + e,
154
+ y: (b * x) + (d * y) + f,
155
+ }
156
+ end
157
+ end
158
+ end