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,475 @@
1
+ = Painting Operators
2
+
3
+ == General
4
+
5
+ Painting operators convert the current path into visible marks on the output
6
+ device. These operators consume the current path (except for clipping operators)
7
+ and use the current graphics state parameters (colors, line width, etc.) to
8
+ determine the appearance of the painted graphics.
9
+
10
+ The two fundamental painting operations are stroking (painting along the path)
11
+ and filling (painting the interior of the path).
12
+
13
+ [[stroke]]
14
+ == stroke
15
+
16
+ === General
17
+
18
+ The `stroke` operator paints a line along the current path using the current
19
+ stroke color and line attributes. The path is consumed by this operation,
20
+ leaving an empty current path.
21
+
22
+ Stroking uses these graphics state parameters:
23
+
24
+ * Stroke color (set by `setrgbcolor`, `setgray`, etc.)
25
+ * Line width (set by `setlinewidth`)
26
+ * Line cap style (set by `setlinecap`)
27
+ * Line join style (set by `setlinejoin`)
28
+ * Miter limit (set by `setmiterlimit`)
29
+ * Dash pattern (set by `setdash`)
30
+
31
+ === Syntax
32
+
33
+ [source,postscript]
34
+ ----
35
+ stroke <1>
36
+ ----
37
+ <1> Operator that strokes and consumes current path
38
+
39
+ Where,
40
+
41
+ Stack effect: `-- `
42
+
43
+ === Examples
44
+
45
+ [example]
46
+ ====
47
+ [source,postscript]
48
+ ----
49
+ newpath
50
+ 50 50 moveto
51
+ 150 150 lineto
52
+ 2 setlinewidth % Set line width to 2 points
53
+ 0 0 0 setrgbcolor % Set stroke color to black
54
+ stroke % Paint the line
55
+ ----
56
+
57
+ Creates a diagonal line from (50, 50) to (150, 150) with 2-point width.
58
+ ====
59
+
60
+ [example]
61
+ ====
62
+ [source,postscript]
63
+ ----
64
+ newpath
65
+ 100 100 50 0 360 arc % Circle path
66
+ 1 0 0 setrgbcolor % Red color
67
+ 3 setlinewidth % 3-point width
68
+ stroke % Stroke circle outline
69
+ ----
70
+
71
+ Draws a red circle outline.
72
+ ====
73
+
74
+ [[fill]]
75
+ == fill
76
+
77
+ === General
78
+
79
+ The `fill` operator fills the interior of the current path with the current
80
+ fill color using the non-zero winding number rule. The path is consumed,
81
+ leaving an empty current path.
82
+
83
+ The non-zero winding rule determines whether a point is inside the path by
84
+ counting path crossings. It handles overlapping paths and paths with multiple
85
+ subpaths.
86
+
87
+ === Syntax
88
+
89
+ [source,postscript]
90
+ ----
91
+ fill <1>
92
+ ----
93
+ <1> Operator that fills and consumes current path
94
+
95
+ Where,
96
+
97
+ Stack effect: `-- `
98
+
99
+ === Examples
100
+
101
+ [example]
102
+ ====
103
+ [source,postscript]
104
+ ----
105
+ newpath
106
+ 50 50 moveto
107
+ 150 50 lineto
108
+ 100 150 lineto
109
+ closepath
110
+ 0 0 1 setrgbcolor % Blue fill color
111
+ fill % Fill the triangle
112
+ ----
113
+
114
+ Creates a solid blue triangle.
115
+ ====
116
+
117
+ [example]
118
+ ====
119
+ [source,postscript]
120
+ ----
121
+ newpath
122
+ 100 100 50 0 360 arc % Circle
123
+ 0.5 0.5 0.5 setrgbcolor % Gray fill
124
+ fill % Fill the circle
125
+ ----
126
+
127
+ Draws a solid gray circle.
128
+ ====
129
+
130
+ === Non-zero winding rule
131
+
132
+ [example]
133
+ ====
134
+ [source,postscript]
135
+ ----
136
+ newpath
137
+ % Outer square (counterclockwise)
138
+ 0 0 moveto
139
+ 200 0 lineto
140
+ 200 200 lineto
141
+ 0 200 lineto
142
+ closepath
143
+
144
+ % Inner square (also counterclockwise)
145
+ 50 50 moveto
146
+ 150 50 lineto
147
+ 150 150 lineto
148
+ 50 150 lineto
149
+ closepath
150
+
151
+ fill
152
+ ----
153
+
154
+ With both paths counterclockwise, both squares are filled. The winding numbers
155
+ add up, keeping both regions inside.
156
+ ====
157
+
158
+ [[eofill]]
159
+ == eofill
160
+
161
+ === General
162
+
163
+ The `eofill` operator fills the interior of the current path using the
164
+ even-odd rule instead of the non-zero winding rule. The path is consumed.
165
+
166
+ The even-odd rule determines whether a point is inside by counting crossings:
167
+ if the count is odd, the point is inside; if even, it's outside. This creates
168
+ alternating filled and unfilled regions for overlapping paths.
169
+
170
+ === Syntax
171
+
172
+ [source,postscript]
173
+ ----
174
+ eofill <1>
175
+ ----
176
+ <1> Operator that fills using even-odd rule
177
+
178
+ Where,
179
+
180
+ Stack effect: `-- `
181
+
182
+ === Examples
183
+
184
+ [example]
185
+ ====
186
+ [source,postscript]
187
+ ----
188
+ newpath
189
+ % Outer rectangle
190
+ 0 0 moveto
191
+ 200 0 lineto
192
+ 200 200 lineto
193
+ 0 200 lineto
194
+ closepath
195
+
196
+ % Inner rectangle (creates a hole)
197
+ 50 50 moveto
198
+ 150 50 lineto
199
+ 150 150 lineto
200
+ 50 150 lineto
201
+ closepath
202
+
203
+ eofill % Creates frame with hole
204
+ ----
205
+
206
+ The even-odd rule creates a rectangular frame: the outer rectangle is filled,
207
+ but the inner rectangle becomes a hole.
208
+ ====
209
+
210
+ [example]
211
+ ====
212
+ [source,postscript]
213
+ ----
214
+ newpath
215
+ 100 100 80 0 360 arc % Outer circle
216
+ closepath
217
+ 100 100 40 0 360 arc % Inner circle
218
+ closepath
219
+ eofill % Creates ring/donut shape
220
+ ----
221
+
222
+ Creates a ring by treating overlapping circles as alternating regions.
223
+ ====
224
+
225
+ [[clip]]
226
+ == clip
227
+
228
+ === General
229
+
230
+ The `clip` operator establishes a clipping path from the current path using the
231
+ non-zero winding rule. Unlike `stroke` and `fill`, `clip` does not consume the
232
+ current path.
233
+
234
+ The clipping path restricts all subsequent painting operations to the interior
235
+ of the path. Only the intersection of painted marks and the clipping region
236
+ becomes visible.
237
+
238
+ Clipping paths can only be made more restrictive, not less. Use `gsave` and
239
+ `grestore` to save and restore the clipping region.
240
+
241
+ === Syntax
242
+
243
+ [source,postscript]
244
+ ----
245
+ clip <1>
246
+ ----
247
+ <1> Operator that establishes clipping path
248
+
249
+ Where,
250
+
251
+ Stack effect: `-- `
252
+
253
+ === Examples
254
+
255
+ [example]
256
+ ====
257
+ [source,postscript]
258
+ ----
259
+ gsave % Save state to restore clipping later
260
+ newpath
261
+ 100 100 50 0 360 arc % Circle
262
+ clip % Clip to circle
263
+
264
+ % Draw something - only visible within circle
265
+ newpath
266
+ 0 0 moveto
267
+ 200 200 lineto
268
+ stroke
269
+ grestore % Restore original clipping
270
+ ----
271
+
272
+ Clips subsequent drawing to a circular region.
273
+ ====
274
+
275
+ [example]
276
+ ====
277
+ [source,postscript]
278
+ ----
279
+ gsave
280
+ % Clip to text shape (if text operators supported)
281
+ newpath
282
+ 50 50 moveto
283
+ 150 50 lineto
284
+ 150 150 lineto
285
+ 50 150 lineto
286
+ closepath
287
+ clip
288
+
289
+ % Fill with pattern or gradient (would be clipped)
290
+ 0.8 0.8 0.8 setrgbcolor
291
+ 0 0 200 200 rectfill
292
+ grestore
293
+ ----
294
+
295
+ Common pattern: create clipping region, paint, then restore.
296
+ ====
297
+
298
+ [[eoclip]]
299
+ == eoclip
300
+
301
+ === General
302
+
303
+ The `eoclip` operator is identical to `clip` except it uses the even-odd rule
304
+ to determine the interior of the clipping path.
305
+
306
+ === Syntax
307
+
308
+ [source,postscript]
309
+ ----
310
+ eoclip <1>
311
+ ----
312
+ <1> Operator that establishes even-odd clipping path
313
+
314
+ Where,
315
+
316
+ Stack effect: `-- `
317
+
318
+ === Examples
319
+
320
+ [example]
321
+ ====
322
+ [source,postscript]
323
+ ----
324
+ gsave
325
+ newpath
326
+ % Outer circle
327
+ 100 100 80 0 360 arc
328
+ closepath
329
+ % Inner circle (creates hole in clip)
330
+ 100 100 40 0 360 arc
331
+ closepath
332
+ eoclip
333
+
334
+ % Draw in ring-shaped region
335
+ 0.5 setgray
336
+ 0 0 200 200 rectfill
337
+ grestore
338
+ ----
339
+
340
+ Creates a ring-shaped clipping region using even-odd rule.
341
+ ====
342
+
343
+ [[stroke-vs-fill]]
344
+ == Stroke vs Fill Comparison
345
+
346
+ === General
347
+
348
+ Understanding when to use `stroke` versus `fill` is fundamental to PostScript
349
+ graphics.
350
+
351
+ === Stroke characteristics
352
+
353
+ * Paints along the path outline
354
+ * Uses stroke color
355
+ * Width controlled by line width
356
+ * Affected by line cap and join styles
357
+ * Path can be open or closed
358
+
359
+ === Fill characteristics
360
+
361
+ * Paints the path interior
362
+ * Uses fill color
363
+ * No width parameter
364
+ * Not affected by line attributes
365
+ * Best with closed paths
366
+
367
+ === Combining stroke and fill
368
+
369
+ [example]
370
+ ====
371
+ [source,postscript]
372
+ ----
373
+ newpath
374
+ 50 50 moveto
375
+ 150 50 lineto
376
+ 100 150 lineto
377
+ closepath
378
+
379
+ gsave
380
+ 0 0 1 setrgbcolor % Blue fill
381
+ fill % Fill consumes path
382
+ grestore
383
+
384
+ % Must recreate path for stroke
385
+ newpath
386
+ 50 50 moveto
387
+ 150 50 lineto
388
+ 100 150 lineto
389
+ closepath
390
+
391
+ 1 0 0 setrgbcolor % Red stroke
392
+ 3 setlinewidth
393
+ stroke
394
+ ----
395
+
396
+ To both fill and stroke a shape, you must either:
397
+ 1. Save state with `gsave`, fill, restore, then stroke
398
+ 2. Or recreate the path after filling
399
+ ====
400
+
401
+ == Path Consumption
402
+
403
+ === General
404
+
405
+ Most painting operators consume the current path, replacing it with an empty
406
+ path. Understanding this behavior is crucial for correctly sequencing
407
+ operations.
408
+
409
+ === Operators that consume the path
410
+
411
+ * `stroke` - Consumes path after stroking
412
+ * `fill` - Consumes path after filling
413
+ * `eofill` - Consumes path after filling
414
+
415
+ === Operators that do not consume the path
416
+
417
+ * `clip` - Preserves path for subsequent operations
418
+ * `eoclip` - Preserves path for subsequent operations
419
+
420
+ === Working with path consumption
421
+
422
+ [example]
423
+ ====
424
+ [source,postscript]
425
+ ----
426
+ % WRONG: Second operation has no path
427
+ newpath
428
+ 50 50 moveto 150 150 lineto
429
+ stroke % Consumes path
430
+ fill % Nothing to fill!
431
+
432
+ % CORRECT: Use gsave/grestore or recreate
433
+ newpath
434
+ 50 50 moveto 150 150 lineto
435
+ gsave
436
+ stroke % Consumes copy of path
437
+ grestore
438
+ fill % Original path preserved
439
+ ----
440
+ ====
441
+
442
+ == Painting Order
443
+
444
+ === General
445
+
446
+ PostScript follows the painter's algorithm: later operations paint over earlier
447
+ ones. Objects are layered in the order they are painted.
448
+
449
+ [example]
450
+ ====
451
+ [source,postscript]
452
+ ----
453
+ % Red square (painted first, underneath)
454
+ newpath
455
+ 0 0 moveto 100 0 lineto 100 100 lineto 0 100 lineto closepath
456
+ 1 0 0 setrgbcolor
457
+ fill
458
+
459
+ % Blue circle (painted second, on top)
460
+ newpath
461
+ 75 75 40 0 360 arc
462
+ 0 0 1 setrgbcolor
463
+ fill
464
+ ----
465
+
466
+ The blue circle appears on top of the red square because it was painted later.
467
+ ====
468
+
469
+ == See Also
470
+
471
+ * link:path-construction.adoc[Path Construction] - Building paths to paint
472
+ * link:graphics-state.adoc[Graphics State] - Setting colors and line attributes
473
+ * link:../graphics-model.adoc#painting-model[Painting Model] - Conceptual
474
+ overview
475
+ * link:index.adoc[Back to Operator Reference]