postsvg 0.1.0 → 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 (201) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +105 -0
  3. data/CLAUDE.md +173 -0
  4. data/Gemfile +2 -3
  5. data/README.adoc +456 -179
  6. data/Rakefile +100 -0
  7. data/TODO.roadmap/00-architecture.md +139 -0
  8. data/TODO.roadmap/01-autoload-migration.md +39 -0
  9. data/TODO.roadmap/02-isolate-dormant-code.md +51 -0
  10. data/TODO.roadmap/03-domain-model.md +66 -0
  11. data/TODO.roadmap/04-lexer.md +40 -0
  12. data/TODO.roadmap/05-parser.md +43 -0
  13. data/TODO.roadmap/06-graphics-state.md +45 -0
  14. data/TODO.roadmap/07-matrix-and-color.md +37 -0
  15. data/TODO.roadmap/08-svg-builder.md +51 -0
  16. data/TODO.roadmap/09-renderer.md +52 -0
  17. data/TODO.roadmap/10-visitor.md +58 -0
  18. data/TODO.roadmap/11-operator-coverage.md +103 -0
  19. data/TODO.roadmap/12-svg-domain.md +62 -0
  20. data/TODO.roadmap/13-translation-handlers.md +69 -0
  21. data/TODO.roadmap/14-ps-serializer.md +49 -0
  22. data/TODO.roadmap/15-cli-and-public-api.md +47 -0
  23. data/TODO.roadmap/16-specs.md +84 -0
  24. data/TODO.roadmap/17-docs-sync.md +47 -0
  25. data/TODO.roadmap/18-performance-and-determinism.md +47 -0
  26. data/TODO.roadmap/19-error-model.md +45 -0
  27. data/TODO.roadmap/20-font-and-text.md +46 -0
  28. data/TODO.roadmap/21-images.md +45 -0
  29. data/TODO.roadmap/22-forms-and-resources.md +25 -0
  30. data/TODO.roadmap/23-level2-level3.md +52 -0
  31. data/TODO.roadmap/24-ci-and-release.md +42 -0
  32. data/TODO.roadmap/README.md +77 -0
  33. data/docs/.gitignore +29 -0
  34. data/docs/CHANGELOG.md +114 -0
  35. data/docs/COMPLETE_DOCUMENTATION_STATUS.md +376 -0
  36. data/docs/DEPLOYMENT.md +456 -0
  37. data/docs/DEPLOYMENT_INSTRUCTIONS.md +229 -0
  38. data/docs/DOCUMENTATION_PLAN.md +425 -0
  39. data/docs/FINAL_SUMMARY.md +657 -0
  40. data/docs/Gemfile +15 -0
  41. data/docs/README.md +327 -0
  42. data/docs/_config.yml +99 -0
  43. data/docs/advanced-topics.adoc +370 -0
  44. data/docs/api-reference/colors.adoc +705 -0
  45. data/docs/api-reference/converter.adoc +699 -0
  46. data/docs/api-reference/execution-context.adoc +1210 -0
  47. data/docs/api-reference/graphics-state.adoc +1070 -0
  48. data/docs/api-reference/interpreter.adoc +810 -0
  49. data/docs/api-reference/matrix.adoc +1179 -0
  50. data/docs/api-reference/path-builder.adoc +1284 -0
  51. data/docs/api-reference/postsvg-module.adoc +388 -0
  52. data/docs/api-reference/svg-generator.adoc +891 -0
  53. data/docs/api-reference/tokenizer.adoc +925 -0
  54. data/docs/api-reference.adoc +221 -0
  55. data/docs/architecture/command-registry.adoc +1191 -0
  56. data/docs/architecture/conversion-pipeline.adoc +746 -0
  57. data/docs/architecture/design-decisions.adoc +999 -0
  58. data/docs/architecture/generator-stage.adoc +1115 -0
  59. data/docs/architecture/graphics-state-model.adoc +1089 -0
  60. data/docs/architecture/interpreter-stage.adoc +1125 -0
  61. data/docs/architecture/parser-stage.adoc +1051 -0
  62. data/docs/architecture.adoc +354 -0
  63. data/docs/cli-reference/batch-command.adoc +616 -0
  64. data/docs/cli-reference/check-command.adoc +677 -0
  65. data/docs/cli-reference/cli-options.adoc +802 -0
  66. data/docs/cli-reference/convert-command.adoc +462 -0
  67. data/docs/cli-reference/version-command.adoc +296 -0
  68. data/docs/cli-reference.adoc +317 -0
  69. data/docs/concepts/conversion-pipeline.adoc +903 -0
  70. data/docs/concepts/coordinate-systems.adoc +836 -0
  71. data/docs/concepts/graphics-state.adoc +861 -0
  72. data/docs/concepts/path-operations.adoc +1076 -0
  73. data/docs/concepts/postscript-language.adoc +859 -0
  74. data/docs/concepts/svg-generation.adoc +937 -0
  75. data/docs/concepts.adoc +198 -0
  76. data/docs/contributing.adoc +443 -0
  77. data/docs/development.adoc +420 -0
  78. data/docs/faq.adoc +493 -0
  79. data/docs/getting-started/basic-usage.adoc +538 -0
  80. data/docs/getting-started/common-workflows.adoc +577 -0
  81. data/docs/getting-started/first-conversion.adoc +492 -0
  82. data/docs/getting-started/installation.adoc +534 -0
  83. data/docs/getting-started.adoc +94 -0
  84. data/docs/index.adoc +248 -0
  85. data/docs/optimization.adoc +196 -0
  86. data/docs/ps2svg_compatibility.adoc +149 -0
  87. data/docs/quick-reference.adoc +453 -0
  88. data/docs/sitemap.adoc +337 -0
  89. data/docs/troubleshooting.adoc +486 -0
  90. data/docs/validation.adoc +772 -0
  91. data/exe/postsvg +1 -0
  92. data/lib/postsvg/cli.rb +104 -57
  93. data/lib/postsvg/color.rb +132 -0
  94. data/lib/postsvg/errors.rb +68 -3
  95. data/lib/postsvg/format_number.rb +22 -0
  96. data/lib/postsvg/graphics_context.rb +80 -0
  97. data/lib/postsvg/graphics_stack.rb +43 -0
  98. data/lib/postsvg/model/literals/array.rb +41 -0
  99. data/lib/postsvg/model/literals/dictionary.rb +34 -0
  100. data/lib/postsvg/model/literals/hex.rb +37 -0
  101. data/lib/postsvg/model/literals/name.rb +40 -0
  102. data/lib/postsvg/model/literals/number.rb +36 -0
  103. data/lib/postsvg/model/literals/procedure.rb +41 -0
  104. data/lib/postsvg/model/literals/string.rb +30 -0
  105. data/lib/postsvg/model/literals.rb +19 -0
  106. data/lib/postsvg/model/operator.rb +58 -0
  107. data/lib/postsvg/model/operators/arithmetic.rb +264 -0
  108. data/lib/postsvg/model/operators/boolean.rb +182 -0
  109. data/lib/postsvg/model/operators/color.rb +74 -0
  110. data/lib/postsvg/model/operators/container.rb +186 -0
  111. data/lib/postsvg/model/operators/control_flow.rb +119 -0
  112. data/lib/postsvg/model/operators/device.rb +21 -0
  113. data/lib/postsvg/model/operators/dictionary.rb +118 -0
  114. data/lib/postsvg/model/operators/font.rb +121 -0
  115. data/lib/postsvg/model/operators/graphics_state.rb +84 -0
  116. data/lib/postsvg/model/operators/painting.rb +29 -0
  117. data/lib/postsvg/model/operators/path.rb +169 -0
  118. data/lib/postsvg/model/operators/stack.rb +72 -0
  119. data/lib/postsvg/model/operators/transformations.rb +103 -0
  120. data/lib/postsvg/model/operators.rb +89 -0
  121. data/lib/postsvg/model/program.rb +68 -0
  122. data/lib/postsvg/model/token.rb +43 -0
  123. data/lib/postsvg/model.rb +17 -0
  124. data/lib/postsvg/options.rb +29 -0
  125. data/lib/postsvg/renderer.rb +85 -0
  126. data/lib/postsvg/serializer.rb +325 -0
  127. data/lib/postsvg/source/ast_builder.rb +308 -0
  128. data/lib/postsvg/source/lexer.rb +322 -0
  129. data/lib/postsvg/source/operand_stack.rb +55 -0
  130. data/lib/postsvg/source.rb +21 -0
  131. data/lib/postsvg/svg/attribute_parser.rb +45 -0
  132. data/lib/postsvg/svg/clip_path_registry.rb +44 -0
  133. data/lib/postsvg/svg/document.rb +22 -0
  134. data/lib/postsvg/svg/element.rb +84 -0
  135. data/lib/postsvg/svg/elements/circle.rb +36 -0
  136. data/lib/postsvg/svg/elements/clip_path.rb +26 -0
  137. data/lib/postsvg/svg/elements/defs.rb +24 -0
  138. data/lib/postsvg/svg/elements/ellipse.rb +38 -0
  139. data/lib/postsvg/svg/elements/group.rb +37 -0
  140. data/lib/postsvg/svg/elements/image.rb +35 -0
  141. data/lib/postsvg/svg/elements/line.rb +36 -0
  142. data/lib/postsvg/svg/elements/path.rb +32 -0
  143. data/lib/postsvg/svg/elements/polygon.rb +12 -0
  144. data/lib/postsvg/svg/elements/polyline.rb +32 -0
  145. data/lib/postsvg/svg/elements/rect.rb +44 -0
  146. data/lib/postsvg/svg/elements/svg.rb +39 -0
  147. data/lib/postsvg/svg/elements/text.rb +42 -0
  148. data/lib/postsvg/svg/elements.rb +31 -0
  149. data/lib/postsvg/svg/paint.rb +34 -0
  150. data/lib/postsvg/svg/parser.rb +39 -0
  151. data/lib/postsvg/svg/path_data/command.rb +27 -0
  152. data/lib/postsvg/svg/path_data/parser.rb +82 -0
  153. data/lib/postsvg/svg/path_data.rb +17 -0
  154. data/lib/postsvg/svg/stroke.rb +31 -0
  155. data/lib/postsvg/svg/transform_list.rb +59 -0
  156. data/lib/postsvg/svg.rb +22 -0
  157. data/lib/postsvg/svg_builder.rb +249 -0
  158. data/lib/postsvg/translation/arc_converter.rb +86 -0
  159. data/lib/postsvg/translation/bounding_box.rb +59 -0
  160. data/lib/postsvg/translation/context.rb +34 -0
  161. data/lib/postsvg/translation/handler_registry.rb +38 -0
  162. data/lib/postsvg/translation/handlers/circle_handler.rb +28 -0
  163. data/lib/postsvg/translation/handlers/clip_path_handler.rb +13 -0
  164. data/lib/postsvg/translation/handlers/defs_handler.rb +15 -0
  165. data/lib/postsvg/translation/handlers/ellipse_handler.rb +31 -0
  166. data/lib/postsvg/translation/handlers/group_handler.rb +21 -0
  167. data/lib/postsvg/translation/handlers/image_handler.rb +20 -0
  168. data/lib/postsvg/translation/handlers/line_handler.rb +23 -0
  169. data/lib/postsvg/translation/handlers/open_handler.rb +18 -0
  170. data/lib/postsvg/translation/handlers/path_handler.rb +356 -0
  171. data/lib/postsvg/translation/handlers/polygon_handler.rb +33 -0
  172. data/lib/postsvg/translation/handlers/polyline_handler.rb +31 -0
  173. data/lib/postsvg/translation/handlers/rect_handler.rb +27 -0
  174. data/lib/postsvg/translation/handlers/shared.rb +110 -0
  175. data/lib/postsvg/translation/handlers/svg_handler.rb +25 -0
  176. data/lib/postsvg/translation/handlers/text_handler.rb +56 -0
  177. data/lib/postsvg/translation/handlers.rb +25 -0
  178. data/lib/postsvg/translation/ps_renderer.rb +105 -0
  179. data/lib/postsvg/translation/record_emitter.rb +35 -0
  180. data/lib/postsvg/translation.rb +17 -0
  181. data/lib/postsvg/version.rb +1 -1
  182. data/lib/postsvg/visitors/ps_visitor/arithmetic.rb +125 -0
  183. data/lib/postsvg/visitors/ps_visitor/boolean.rb +105 -0
  184. data/lib/postsvg/visitors/ps_visitor/color.rb +53 -0
  185. data/lib/postsvg/visitors/ps_visitor/common.rb +66 -0
  186. data/lib/postsvg/visitors/ps_visitor/container.rb +164 -0
  187. data/lib/postsvg/visitors/ps_visitor/control_flow.rb +110 -0
  188. data/lib/postsvg/visitors/ps_visitor/device.rb +20 -0
  189. data/lib/postsvg/visitors/ps_visitor/dictionary.rb +89 -0
  190. data/lib/postsvg/visitors/ps_visitor/font.rb +93 -0
  191. data/lib/postsvg/visitors/ps_visitor/graphics_state.rb +55 -0
  192. data/lib/postsvg/visitors/ps_visitor/painting.rb +90 -0
  193. data/lib/postsvg/visitors/ps_visitor/path.rb +112 -0
  194. data/lib/postsvg/visitors/ps_visitor/stack.rb +47 -0
  195. data/lib/postsvg/visitors/ps_visitor/transformations.rb +101 -0
  196. data/lib/postsvg/visitors/ps_visitor.rb +208 -0
  197. data/lib/postsvg/visitors.rb +9 -0
  198. data/lib/postsvg.rb +93 -59
  199. data/lychee.toml +86 -0
  200. metadata +216 -11
  201. data/postsvg.gemspec +0 -38
@@ -0,0 +1,1070 @@
1
+ = GraphicsState Class
2
+ :page-nav_order: 5
3
+ :page-parent: API Reference
4
+
5
+ == Purpose
6
+
7
+ The [`GraphicsState`](../../lib/postsvg/graphics_state.rb:5) class manages PostScript graphics state including path construction, color settings, transformations, and rendering parameters. It provides a legacy interface for graphics operations, though most functionality has been migrated to [`ExecutionContext`](execution-context.adoc).
8
+
9
+ == References
10
+
11
+ * link:../index.adoc[Documentation Home]
12
+ * link:../api-reference.adoc[API Reference Overview]
13
+ * link:execution-context.adoc[ExecutionContext Class]
14
+ * link:interpreter.adoc[Interpreter Class]
15
+ * link:../architecture.adoc[Architecture Overview]
16
+
17
+ == Concepts
18
+
19
+ **Graphics State**:: The collection of parameters that control how graphics are rendered, including colors, line width, transformations, and the current path.
20
+
21
+ **Current Path**:: The sequence of path segments (moveto, lineto, curveto) being constructed before rendering.
22
+
23
+ **Current Point**:: The coordinates where the next path segment will begin.
24
+
25
+ **Transformation Matrix**:: A 2D affine transformation matrix that maps coordinates from user space to device space.
26
+
27
+ **Graphics State Stack**:: A stack allowing graphics state to be saved and restored via `save`/`restore` operations.
28
+
29
+ **Color Space**:: The color model used for rendering (RGB, grayscale, CMYK, etc.).
30
+
31
+ == Class Overview
32
+
33
+ The [`GraphicsState`](../../lib/postsvg/graphics_state.rb:5) class is defined in [`lib/postsvg/graphics_state.rb`](../../lib/postsvg/graphics_state.rb:1).
34
+
35
+ **Responsibilities:**
36
+
37
+ * Manage current path construction
38
+ * Track current point coordinates
39
+ * Store color settings (fill and stroke)
40
+ * Maintain transformation matrix
41
+ * Implement graphics state stack (save/restore)
42
+ * Provide coordinate transformation
43
+ * Support Level 3 PostScript features
44
+
45
+ **Note on Usage:**
46
+
47
+ This class represents a legacy architecture component. In the current implementation, most graphics state functionality is handled by [`ExecutionContext`](execution-context.adoc). The `GraphicsState` class is maintained for compatibility but is not actively used in the primary execution path.
48
+
49
+ **Key Components:**
50
+
51
+ * Current path - Array of path segments
52
+ * Current point - (x, y) coordinates
53
+ * Colors - Fill and stroke RGB values
54
+ * Transform matrix - 6-element array [a, b, c, d, e, f]
55
+ * State stack - For save/restore operations
56
+
57
+ == Class Methods
58
+
59
+ === new
60
+
61
+ Create a new GraphicsState with default values.
62
+
63
+ **Syntax:**
64
+
65
+ [source,ruby]
66
+ ----
67
+ graphics_state = Postsvg::GraphicsState.new <1>
68
+ ----
69
+ <1> Initialize graphics state with defaults
70
+
71
+ **Returns:**
72
+
73
+ New `GraphicsState` instance with:
74
+
75
+ * Empty path
76
+ * Current point at origin (0, 0)
77
+ * Line width of 1.0
78
+ * Black fill and stroke colors
79
+ * Identity transformation matrix
80
+ * Empty state stack
81
+
82
+ **Source:**
83
+
84
+ [`lib/postsvg/graphics_state.rb:10-26`](../../lib/postsvg/graphics_state.rb:10)
85
+
86
+ **Default Values:**
87
+
88
+ [source,ruby]
89
+ ----
90
+ @current_path = []
91
+ @current_x = 0
92
+ @current_y = 0
93
+ @line_width = 1.0
94
+ @fill_color = { r: 0, g: 0, b: 0 } # Black
95
+ @stroke_color = { r: 0, g: 0, b: 0 } # Black
96
+ @transform_matrix = [1, 0, 0, 1, 0, 0] # Identity
97
+ @state_stack = []
98
+
99
+ # Level 3 features
100
+ @icc_profile = nil
101
+ @blend_mode = :normal
102
+ @soft_mask = nil
103
+ @opacity_alpha = 1.0
104
+ @shape_alpha = 1.0
105
+ ----
106
+
107
+ .Create graphics state
108
+ [example]
109
+ ====
110
+ [source,ruby]
111
+ ----
112
+ require 'postsvg'
113
+
114
+ gs = Postsvg::GraphicsState.new
115
+
116
+ puts "Line width: #{gs.line_width}" # 1.0
117
+ puts "Current point: (#{gs.current_x}, #{gs.current_y})" # (0, 0)
118
+ puts "Fill color: #{gs.fill_color.inspect}" # {:r=>0, :g=>0, :b=>0}
119
+ puts "Path empty: #{gs.current_path.empty?}" # true
120
+ ----
121
+ ====
122
+
123
+ == Attributes
124
+
125
+ === line_width (read/write)
126
+
127
+ The width of stroked lines.
128
+
129
+ **Type:** Float
130
+
131
+ **Default:** `1.0`
132
+
133
+ **Source:**
134
+
135
+ [`lib/postsvg/graphics_state.rb:6`](../../lib/postsvg/graphics_state.rb:6)
136
+
137
+ .Line width management
138
+ [example]
139
+ ====
140
+ [source,ruby]
141
+ ----
142
+ gs = Postsvg::GraphicsState.new
143
+
144
+ puts gs.line_width # 1.0
145
+
146
+ # Set custom width
147
+ gs.line_width = 2.5
148
+ puts gs.line_width # 2.5
149
+
150
+ # Thin line
151
+ gs.line_width = 0.5
152
+ ----
153
+ ====
154
+
155
+ === current_x, current_y (read/write)
156
+
157
+ Current point coordinates in user space.
158
+
159
+ **Type:** Numeric
160
+
161
+ **Default:** `0`
162
+
163
+ **Source:**
164
+
165
+ [`lib/postsvg/graphics_state.rb:6-7`](../../lib/postsvg/graphics_state.rb:6)
166
+
167
+ .Track current point
168
+ [example]
169
+ ====
170
+ [source,ruby]
171
+ ----
172
+ gs = Postsvg::GraphicsState.new
173
+
174
+ puts "(#{gs.current_x}, #{gs.current_y})" # (0, 0)
175
+
176
+ # Update via path operations
177
+ gs.moveto(100, 200)
178
+ puts "(#{gs.current_x}, #{gs.current_y})" # (100, 200)
179
+
180
+ gs.lineto(150, 250)
181
+ puts "(#{gs.current_x}, #{gs.current_y})" # (150, 250)
182
+ ----
183
+ ====
184
+
185
+ === current_path (read-only)
186
+
187
+ Array of path segment objects.
188
+
189
+ **Type:** Array of hashes
190
+
191
+ **Default:** `[]`
192
+
193
+ **Source:**
194
+
195
+ [`lib/postsvg/graphics_state.rb:8`](../../lib/postsvg/graphics_state.rb:8)
196
+
197
+ **Path Segment Structure:**
198
+
199
+ Each segment is a hash with a `:type` and coordinates:
200
+
201
+ [source,ruby]
202
+ ----
203
+ # moveto segment
204
+ { type: :moveto, x: 10, y: 20 }
205
+
206
+ # lineto segment
207
+ { type: :lineto, x: 30, y: 40 }
208
+
209
+ # curveto segment
210
+ { type: :curveto, x1: 10, y1: 20, x2: 30, y2: 40, x3: 50, y3: 60 }
211
+
212
+ # closepath segment
213
+ { type: :closepath }
214
+ ----
215
+
216
+ .Inspect path
217
+ [example]
218
+ ====
219
+ [source,ruby]
220
+ ----
221
+ gs = Postsvg::GraphicsState.new
222
+
223
+ gs.moveto(10, 20)
224
+ gs.lineto(30, 40)
225
+ gs.closepath
226
+
227
+ gs.current_path.each do |segment|
228
+ case segment[:type]
229
+ when :moveto
230
+ puts "Move to (#{segment[:x]}, #{segment[:y]})"
231
+ when :lineto
232
+ puts "Line to (#{segment[:x]}, #{segment[:y]})"
233
+ when :closepath
234
+ puts "Close path"
235
+ end
236
+ end
237
+ ----
238
+ ====
239
+
240
+ === fill_color, stroke_color (read-only)
241
+
242
+ RGB color values for fill and stroke operations.
243
+
244
+ **Type:** Hash with `:r`, `:g`, `:b` keys
245
+
246
+ **Values:** 0.0 to 1.0 (not 0-255)
247
+
248
+ **Default:** `{ r: 0, g: 0, b: 0 }` (black)
249
+
250
+ **Source:**
251
+
252
+ [`lib/postsvg/graphics_state.rb:8`](../../lib/postsvg/graphics_state.rb:8)
253
+
254
+ .Access colors
255
+ [example]
256
+ ====
257
+ [source,ruby]
258
+ ----
259
+ gs = Postsvg::GraphicsState.new
260
+
261
+ # Default black
262
+ puts gs.fill_color # {:r=>0, :g=>0, :b=>0}
263
+ puts gs.stroke_color # {:r=>0, :g=>0, :b=>0}
264
+
265
+ # Set red
266
+ gs.set_rgb_color(1, 0, 0)
267
+ puts gs.fill_color # {:r=>1, :g=>0, :b=>0}
268
+
269
+ # Get as hex
270
+ hex = gs.fill_color_hex
271
+ puts hex # "#ff0000"
272
+ ----
273
+ ====
274
+
275
+ === Level 3 Attributes
276
+
277
+ ==== icc_profile (read/write)
278
+
279
+ ICC color profile for advanced color management.
280
+
281
+ **Type:** Object or nil
282
+
283
+ **Default:** `nil`
284
+
285
+ **Source:**
286
+
287
+ [`lib/postsvg/graphics_state.rb:6-7`](../../lib/postsvg/graphics_state.rb:6)
288
+
289
+ ==== blend_mode (read/write)
290
+
291
+ Blend mode for compositing operations.
292
+
293
+ **Type:** Symbol
294
+
295
+ **Default:** `:normal`
296
+
297
+ **Source:**
298
+
299
+ [`lib/postsvg/graphics_state.rb:6-7`](../../lib/postsvg/graphics_state.rb:6)
300
+
301
+ ==== soft_mask (read/write)
302
+
303
+ Soft mask for transparency effects.
304
+
305
+ **Type:** Object or nil
306
+
307
+ **Default:** `nil`
308
+
309
+ **Source:**
310
+
311
+ [`lib/postsvg/graphics_state.rb:6-7`](../../lib/postsvg/graphics_state.rb:6)
312
+
313
+ ==== opacity_alpha (read/write)
314
+
315
+ Opacity alpha value.
316
+
317
+ **Type:** Float (0.0 to 1.0)
318
+
319
+ **Default:** `1.0` (fully opaque)
320
+
321
+ **Source:**
322
+
323
+ [`lib/postsvg/graphics_state.rb:6-7`](../../lib/postsvg/graphics_state.rb:6)
324
+
325
+ ==== shape_alpha (read/write)
326
+
327
+ Shape alpha value for blending.
328
+
329
+ **Type:** Float (0.0 to 1.0)
330
+
331
+ **Default:** `1.0`
332
+
333
+ **Source:**
334
+
335
+ [`lib/postsvg/graphics_state.rb:6-7`](../../lib/postsvg/graphics_state.rb:6)
336
+
337
+ .Level 3 features
338
+ [example]
339
+ ====
340
+ [source,ruby]
341
+ ----
342
+ gs = Postsvg::GraphicsState.new
343
+
344
+ # Set transparency
345
+ gs.opacity_alpha = 0.5 # 50% transparent
346
+ gs.shape_alpha = 0.75
347
+
348
+ # Set blend mode
349
+ gs.blend_mode = :multiply
350
+
351
+ puts "Opacity: #{gs.opacity_alpha}" # 0.5
352
+ puts "Blend mode: #{gs.blend_mode}" # :multiply
353
+ ----
354
+ ====
355
+
356
+ == Path Construction Methods
357
+
358
+ === moveto
359
+
360
+ Move current point to new coordinates.
361
+
362
+ **Syntax:**
363
+
364
+ [source,ruby]
365
+ ----
366
+ gs.moveto(x, y) <1>
367
+ ----
368
+ <1> Move to (x, y) starting a new subpath
369
+
370
+ **Where:**
371
+
372
+ `x`:: X coordinate in user space
373
+ `y`:: Y coordinate in user space
374
+
375
+ **Source:**
376
+
377
+ [`lib/postsvg/graphics_state.rb:29-34`](../../lib/postsvg/graphics_state.rb:29)
378
+
379
+ **Behavior:**
380
+
381
+ * Transforms coordinates via transformation matrix
382
+ * Updates current point
383
+ * Adds moveto segment to path
384
+
385
+ .Moveto example
386
+ [example]
387
+ ====
388
+ [source,ruby]
389
+ ----
390
+ gs = Postsvg::GraphicsState.new
391
+
392
+ gs.moveto(10, 20)
393
+
394
+ puts gs.current_path.last
395
+ # {:type=>:moveto, :x=>10, :y=>20}
396
+
397
+ puts "(#{gs.current_x}, #{gs.current_y})"
398
+ # (10, 20)
399
+ ----
400
+ ====
401
+
402
+ === lineto
403
+
404
+ Draw line from current point to new coordinates.
405
+
406
+ **Syntax:**
407
+
408
+ [source,ruby]
409
+ ----
410
+ gs.lineto(x, y) <1>
411
+ ----
412
+ <1> Draw line to (x, y)
413
+
414
+ **Where:**
415
+
416
+ `x`:: X coordinate in user space
417
+ `y`:: Y coordinate in user space
418
+
419
+ **Source:**
420
+
421
+ [`lib/postsvg/graphics_state.rb:36-41`](../../lib/postsvg/graphics_state.rb:36)
422
+
423
+ **Behavior:**
424
+
425
+ * Transforms coordinates via transformation matrix
426
+ * Updates current point
427
+ * Adds lineto segment to path
428
+
429
+ .Lineto example
430
+ [example]
431
+ ====
432
+ [source,ruby]
433
+ ----
434
+ gs = Postsvg::GraphicsState.new
435
+
436
+ gs.moveto(10, 20)
437
+ gs.lineto(30, 40)
438
+ gs.lineto(50, 60)
439
+
440
+ # Path now has: moveto, lineto, lineto
441
+ puts gs.current_path.length # 3
442
+ puts "(#{gs.current_x}, #{gs.current_y})" # (50, 60)
443
+ ----
444
+ ====
445
+
446
+ === rlineto
447
+
448
+ Draw line relative to current point.
449
+
450
+ **Syntax:**
451
+
452
+ [source,ruby]
453
+ ----
454
+ gs.rlineto(dx, dy) <1>
455
+ ----
456
+ <1> Draw line by relative offset (dx, dy)
457
+
458
+ **Where:**
459
+
460
+ `dx`:: X offset from current point
461
+ `dy`:: Y offset from current point
462
+
463
+ **Source:**
464
+
465
+ [`lib/postsvg/graphics_state.rb:43-46`](../../lib/postsvg/graphics_state.rb:43)
466
+
467
+ .Relative lineto
468
+ [example]
469
+ ====
470
+ [source,ruby]
471
+ ----
472
+ gs = Postsvg::GraphicsState.new
473
+
474
+ gs.moveto(10, 20)
475
+
476
+ # Draw 30 units right, 40 units up
477
+ gs.rlineto(30, 40)
478
+
479
+ puts "(#{gs.current_x}, #{gs.current_y})" # (40, 60)
480
+ ----
481
+ ====
482
+
483
+ === curveto
484
+
485
+ Draw Bézier curve from current point.
486
+
487
+ **Syntax:**
488
+
489
+ [source,ruby]
490
+ ----
491
+ gs.curveto(x1, y1, x2, y2, x3, y3) <1>
492
+ ----
493
+ <1> Draw cubic Bézier curve with two control points
494
+
495
+ **Where:**
496
+
497
+ `x1, y1`:: First control point
498
+ `x2, y2`:: Second control point
499
+ `x3, y3`:: End point
500
+
501
+ **Source:**
502
+
503
+ [`lib/postsvg/graphics_state.rb:48-62`](../../lib/postsvg/graphics_state.rb:48)
504
+
505
+ **Behavior:**
506
+
507
+ * Transforms all coordinates via transformation matrix
508
+ * Updates current point to (x3, y3)
509
+ * Adds curveto segment to path
510
+
511
+ .Curveto example
512
+ [example]
513
+ ====
514
+ [source,ruby]
515
+ ----
516
+ gs = Postsvg::GraphicsState.new
517
+
518
+ gs.moveto(10, 10)
519
+ gs.curveto(20, 40, 40, 40, 50, 10)
520
+
521
+ segment = gs.current_path.last
522
+ puts segment[:type] # :curveto
523
+ puts "Control 1: (#{segment[:x1]}, #{segment[:y1]})"
524
+ puts "Control 2: (#{segment[:x2]}, #{segment[:y2]})"
525
+ puts "End: (#{segment[:x3]}, #{segment[:y3]})"
526
+ ----
527
+ ====
528
+
529
+ === closepath
530
+
531
+ Close current subpath by connecting to start point.
532
+
533
+ **Syntax:**
534
+
535
+ [source,ruby]
536
+ ----
537
+ gs.closepath <1>
538
+ ----
539
+ <1> Add closepath segment to path
540
+
541
+ **Source:**
542
+
543
+ [`lib/postsvg/graphics_state.rb:64-66`](../../lib/postsvg/graphics_state.rb:64)
544
+
545
+ .Closepath example
546
+ [example]
547
+ ====
548
+ [source,ruby]
549
+ ----
550
+ gs = Postsvg::GraphicsState.new
551
+
552
+ # Draw triangle
553
+ gs.moveto(10, 10)
554
+ gs.lineto(50, 10)
555
+ gs.lineto(30, 40)
556
+ gs.closepath
557
+
558
+ # Path is now closed triangle
559
+ puts gs.current_path.length # 4 segments
560
+ puts gs.current_path.last[:type] # :closepath
561
+ ----
562
+ ====
563
+
564
+ === newpath
565
+
566
+ Clear current path and start new one.
567
+
568
+ **Syntax:**
569
+
570
+ [source,ruby]
571
+ ----
572
+ gs.newpath <1>
573
+ ----
574
+ <1> Clear all path segments
575
+
576
+ **Source:**
577
+
578
+ [`lib/postsvg/graphics_state.rb:68-70`](../../lib/postsvg/graphics_state.rb:68)
579
+
580
+ .Newpath example
581
+ [example]
582
+ ====
583
+ [source,ruby]
584
+ ----
585
+ gs = Postsvg::GraphicsState.new
586
+
587
+ gs.moveto(10, 10)
588
+ gs.lineto(20, 20)
589
+
590
+ puts gs.current_path.length # 2
591
+
592
+ gs.newpath
593
+
594
+ puts gs.current_path.length # 0
595
+ puts gs.current_path.empty? # true
596
+ ----
597
+ ====
598
+
599
+ == Color Methods
600
+
601
+ === set_rgb_color
602
+
603
+ Set both fill and stroke colors using RGB.
604
+
605
+ **Syntax:**
606
+
607
+ [source,ruby]
608
+ ----
609
+ gs.set_rgb_color(r, g, b) <1>
610
+ ----
611
+ <1> Set RGB color for fill and stroke
612
+
613
+ **Where:**
614
+
615
+ `r`:: Red component (0.0 to 1.0)
616
+ `g`:: Green component (0.0 to 1.0)
617
+ `b`:: Blue component (0.0 to 1.0)
618
+
619
+ **Source:**
620
+
621
+ [`lib/postsvg/graphics_state.rb:73-77`](../../lib/postsvg/graphics_state.rb:73)
622
+
623
+ .Set RGB color
624
+ [example]
625
+ ====
626
+ [source,ruby]
627
+ ----
628
+ gs = Postsvg::GraphicsState.new
629
+
630
+ # Set to red
631
+ gs.set_rgb_color(1, 0, 0)
632
+
633
+ puts gs.fill_color # {:r=>1, :g=>0, :b=>0}
634
+ puts gs.stroke_color # {:r=>1, :g=>0, :b=>0}
635
+
636
+ # Set to semi-transparent blue
637
+ gs.set_rgb_color(0, 0, 0.5)
638
+
639
+ # Convert to hex
640
+ puts gs.fill_color_hex # "#000080"
641
+ ----
642
+ ====
643
+
644
+ === set_gray
645
+
646
+ Set grayscale color (same value for R, G, B).
647
+
648
+ **Syntax:**
649
+
650
+ [source,ruby]
651
+ ----
652
+ gs.set_gray(gray) <1>
653
+ ----
654
+ <1> Set grayscale value for fill and stroke
655
+
656
+ **Where:**
657
+
658
+ `gray`:: Gray level (0.0 = black, 1.0 = white)
659
+
660
+ **Source:**
661
+
662
+ [`lib/postsvg/graphics_state.rb:79-81`](../../lib/postsvg/graphics_state.rb:79)
663
+
664
+ .Set grayscale
665
+ [example]
666
+ ====
667
+ [source,ruby]
668
+ ----
669
+ gs = Postsvg::GraphicsState.new
670
+
671
+ # Set to 50% gray
672
+ gs.set_gray(0.5)
673
+
674
+ puts gs.fill_color # {:r=>0.5, :g=>0.5, :b=>0.5}
675
+
676
+ # White
677
+ gs.set_gray(1.0)
678
+ puts gs.fill_color_hex # "#ffffff"
679
+
680
+ # Black
681
+ gs.set_gray(0)
682
+ puts gs.fill_color_hex # "#000000"
683
+ ----
684
+ ====
685
+
686
+ === rgb_to_hex
687
+
688
+ Convert RGB values to hex color string.
689
+
690
+ **Syntax:**
691
+
692
+ [source,ruby]
693
+ ----
694
+ hex = gs.rgb_to_hex(r, g, b) <1>
695
+ ----
696
+ <1> Convert RGB components to hex string
697
+
698
+ **Where:**
699
+
700
+ `r, g, b`:: Color components (0.0 to 1.0)
701
+
702
+ **Returns:**
703
+
704
+ String in format `"#RRGGBB"`
705
+
706
+ **Source:**
707
+
708
+ [`lib/postsvg/graphics_state.rb:153-155`](../../lib/postsvg/graphics_state.rb:153)
709
+
710
+ .RGB to hex conversion
711
+ [example]
712
+ ====
713
+ [source,ruby]
714
+ ----
715
+ gs = Postsvg::GraphicsState.new
716
+
717
+ hex = gs.rgb_to_hex(1, 0, 0)
718
+ puts hex # "#ff0000" (red)
719
+
720
+ hex = gs.rgb_to_hex(0, 0.5, 1)
721
+ puts hex # "#0080ff" (light blue)
722
+
723
+ hex = gs.rgb_to_hex(0.5, 0.5, 0.5)
724
+ puts hex # "#808080" (gray)
725
+ ----
726
+ ====
727
+
728
+ === fill_color_hex
729
+
730
+ Get current fill color as hex string.
731
+
732
+ **Syntax:**
733
+
734
+ [source,ruby]
735
+ ----
736
+ hex = gs.fill_color_hex <1>
737
+ ----
738
+ <1> Convert current fill color to hex
739
+
740
+ **Returns:**
741
+
742
+ Hex color string or `"none"` if not RGB
743
+
744
+ **Source:**
745
+
746
+ [`lib/postsvg/graphics_state.rb:157-162`](../../lib/postsvg/graphics_state.rb:157)
747
+
748
+ === stroke_color_hex
749
+
750
+ Get current stroke color as hex string.
751
+
752
+ **Syntax:**
753
+
754
+ [source,ruby]
755
+ ----
756
+ hex = gs.stroke_color_hex <1>
757
+ ----
758
+ <1> Convert current stroke color to hex
759
+
760
+ **Returns:**
761
+
762
+ Hex color string or `"none"` if not RGB
763
+
764
+ **Source:**
765
+
766
+ [`lib/postsvg/graphics_state.rb:164-169`](../../lib/postsvg/graphics_state.rb:164)
767
+
768
+ .Color hex conversion
769
+ [example]
770
+ ====
771
+ [source,ruby]
772
+ ----
773
+ gs = Postsvg::GraphicsState.new
774
+
775
+ gs.set_rgb_color(1, 0.5, 0) # Orange
776
+
777
+ puts gs.fill_color_hex # "#ff8000"
778
+ puts gs.stroke_color_hex # "#ff8000"
779
+
780
+ # Change to blue
781
+ gs.set_rgb_color(0, 0, 1)
782
+ puts gs.fill_color_hex # "#0000ff"
783
+ ----
784
+ ====
785
+
786
+ == Graphics State Stack
787
+
788
+ === save
789
+
790
+ Save current graphics state onto stack.
791
+
792
+ **Syntax:**
793
+
794
+ [source,ruby]
795
+ ----
796
+ gs.save <1>
797
+ ----
798
+ <1> Push current state onto graphics state stack
799
+
800
+ **Source:**
801
+
802
+ [`lib/postsvg/graphics_state.rb:84-99`](../../lib/postsvg/graphics_state.rb:84)
803
+
804
+ **Saved State:**
805
+
806
+ * Current path (copy)
807
+ * Current point (x, y)
808
+ * Line width
809
+ * Fill color (copy)
810
+ * Stroke color (copy)
811
+ * Transformation matrix (copy)
812
+ * All Level 3 properties
813
+
814
+ .Save graphics state
815
+ [example]
816
+ ====
817
+ [source,ruby]
818
+ ----
819
+ gs = Postsvg::GraphicsState.new
820
+
821
+ # Set initial state
822
+ gs.set_rgb_color(1, 0, 0) # Red
823
+ gs.line_width = 2
824
+
825
+ # Save state
826
+ gs.save
827
+
828
+ # Modify state
829
+ gs.set_rgb_color(0, 0, 1) # Blue
830
+ gs.line_width = 5
831
+
832
+ puts gs.fill_color_hex # "#0000ff"
833
+ puts gs.line_width # 5
834
+
835
+ # Restore state
836
+ gs.restore
837
+
838
+ puts gs.fill_color_hex # "#ff0000"
839
+ puts gs.line_width # 2
840
+ ----
841
+ ====
842
+
843
+ === restore
844
+
845
+ Restore previously saved graphics state.
846
+
847
+ **Syntax:**
848
+
849
+ [source,ruby]
850
+ ----
851
+ gs.restore <1>
852
+ ----
853
+ <1> Pop state from stack and apply
854
+
855
+ **Source:**
856
+
857
+ [`lib/postsvg/graphics_state.rb:101-117`](../../lib/postsvg/graphics_state.rb:101)
858
+
859
+ **Behavior:**
860
+
861
+ Does nothing if state stack is empty.
862
+
863
+ .Nested save/restore
864
+ [example]
865
+ ====
866
+ [source,ruby]
867
+ ----
868
+ gs = Postsvg::GraphicsState.new
869
+
870
+ gs.set_rgb_color(1, 0, 0) # Red
871
+ gs.save
872
+
873
+ gs.set_rgb_color(0, 1, 0) # Green
874
+ gs.save
875
+
876
+ gs.set_rgb_color(0, 0, 1) # Blue
877
+ puts gs.fill_color_hex # "#0000ff"
878
+
879
+ gs.restore
880
+ puts gs.fill_color_hex # "#00ff00"
881
+
882
+ gs.restore
883
+ puts gs.fill_color_hex # "#ff0000"
884
+ ----
885
+ ====
886
+
887
+ == Transformation Methods
888
+
889
+ === translate
890
+
891
+ Apply translation transformation.
892
+
893
+ **Syntax:**
894
+
895
+ [source,ruby]
896
+ ----
897
+ gs.translate(tx, ty) <1>
898
+ ----
899
+ <1> Translate by (tx, ty)
900
+
901
+ **Where:**
902
+
903
+ `tx`:: X translation amount
904
+ `ty`:: Y translation amount
905
+
906
+ **Source:**
907
+
908
+ [`lib/postsvg/graphics_state.rb:120-124`](../../lib/postsvg/graphics_state.rb:120)
909
+
910
+ **Effect:**
911
+
912
+ Modifies transformation matrix to shift coordinate system.
913
+
914
+ .Translation example
915
+ [example]
916
+ ====
917
+ [source,ruby]
918
+ ----
919
+ gs = Postsvg::GraphicsState.new
920
+
921
+ # Translate 100 right, 50 up
922
+ gs.translate(100, 50)
923
+
924
+ # Draw at "origin" in new coordinate system
925
+ gs.moveto(0, 0)
926
+
927
+ # Actually at (100, 50) in device space
928
+ puts "(#{gs.current_x}, #{gs.current_y})" # (100, 50)
929
+ ----
930
+ ====
931
+
932
+ === scale
933
+
934
+ Apply scaling transformation.
935
+
936
+ **Syntax:**
937
+
938
+ [source,ruby]
939
+ ----
940
+ gs.scale(sx, sy) <1>
941
+ ----
942
+ <1> Scale by factors (sx, sy)
943
+
944
+ **Where:**
945
+
946
+ `sx`:: X scale factor
947
+ `sy`:: Y scale factor
948
+
949
+ **Source:**
950
+
951
+ [`lib/postsvg/graphics_state.rb:126-132`](../../lib/postsvg/graphics_state.rb:126)
952
+
953
+ .Scaling example
954
+ [example]
955
+ ====
956
+ [source,ruby]
957
+ ----
958
+ gs = Postsvg::GraphicsState.new
959
+
960
+ # Scale 2x in X, 3x in Y
961
+ gs.scale(2, 3)
962
+
963
+ # Draw unit square
964
+ gs.moveto(0, 0)
965
+ gs.lineto(1, 0)
966
+ gs.lineto(1, 1)
967
+ gs.lineto(0, 1)
968
+ gs.closepath
969
+
970
+ # Actually 2x3 rectangle in device space
971
+ ----
972
+ ====
973
+
974
+ === rotate
975
+
976
+ Apply rotation transformation.
977
+
978
+ **Syntax:**
979
+
980
+ [source,ruby]
981
+ ----
982
+ gs.rotate(angle) <1>
983
+ ----
984
+ <1> Rotate by angle in degrees
985
+
986
+ **Where:**
987
+
988
+ `angle`:: Rotation angle in degrees (positive = counter-clockwise)
989
+
990
+ **Source:**
991
+
992
+ [`lib/postsvg/graphics_state.rb:134-150`](../../lib/postsvg/graphics_state.rb:134)
993
+
994
+ .Rotation example
995
+ [example]
996
+ ====
997
+ [source,ruby]
998
+ ----
999
+ gs = Postsvg::GraphicsState.new
1000
+
1001
+ # Rotate 45 degrees
1002
+ gs.rotate(45)
1003
+
1004
+ # Draw horizontal line in rotated space
1005
+ gs.moveto(0, 0)
1006
+ gs.lineto(100, 0)
1007
+
1008
+ # Line actually at 45-degree angle in device space
1009
+ ----
1010
+ ====
1011
+
1012
+ ## Usage Notes
1013
+
1014
+ === Legacy Status
1015
+
1016
+ **Important:** This class is part of the legacy architecture. The current implementation primarily uses [`ExecutionContext`](execution-context.adoc) for graphics state management.
1017
+
1018
+ **Current Usage:**
1019
+
1020
+ * Not actively used in primary execution path
1021
+ * Maintained for compatibility
1022
+ * May be referenced by legacy code or tests
1023
+
1024
+ **Recommended Alternative:**
1025
+
1026
+ Use [`ExecutionContext`](execution-context.adoc) for all new code:
1027
+
1028
+ [source,ruby]
1029
+ ----
1030
+ # Instead of GraphicsState
1031
+ context = Postsvg::ExecutionContext.new
1032
+
1033
+ # Access graphics state via context
1034
+ context.graphics_state[:fill] = "red"
1035
+ context.graphics_state[:stroke_width] = 2
1036
+ ----
1037
+
1038
+ === Coordinate Transformations
1039
+
1040
+ All path operations automatically apply the transformation matrix:
1041
+
1042
+ [source,ruby]
1043
+ ----
1044
+ gs = Postsvg::GraphicsState.new
1045
+
1046
+ gs.translate(10, 20)
1047
+ gs.scale(2, 2)
1048
+
1049
+ # Coordinates are transformed before being added to path
1050
+ gs.moveto(5, 5) # Becomes (20, 30) after transforms
1051
+ ----
1052
+
1053
+ ## Thread Safety
1054
+
1055
+ The `GraphicsState` class is **not thread-safe**. Each thread should have its own instance.
1056
+
1057
+ == Next Steps
1058
+
1059
+ * Review link:execution-context.adoc[ExecutionContext] for current state management
1060
+ * Learn about link:interpreter.adoc[Interpreter Class] for execution flow
1061
+ * See link:../architecture.adoc[Architecture] for system design
1062
+ * Check link:converter.adoc[Converter Class] for high-level API
1063
+
1064
+ == Bibliography
1065
+
1066
+ * link:execution-context.adoc[ExecutionContext Documentation]
1067
+ * link:interpreter.adoc[Interpreter Class Documentation]
1068
+ * link:converter.adoc[Converter Class Documentation]
1069
+ * link:../architecture.adoc[Architecture Overview]
1070
+ * link:https://www.adobe.com/jp/print/postscript/pdfs/PLRM.pdf[PostScript Language Reference Manual]