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,479 @@
1
+ = Transformation Operators
2
+
3
+ == General
4
+
5
+ Transformation operators modify the current transformation matrix (CTM), which
6
+ maps user space coordinates to device space. Transformations affect all
7
+ subsequent graphics operations until the CTM is modified again or the graphics
8
+ state is restored.
9
+
10
+ The three basic transformations are translation, scaling, and rotation. These
11
+ can be combined to produce complex coordinate system changes.
12
+
13
+ [[translate]]
14
+ == translate
15
+
16
+ === General
17
+
18
+ The `translate` operator moves the origin of the user coordinate system to a
19
+ new location. All subsequent coordinates are interpreted relative to this new
20
+ origin.
21
+
22
+ Translation is one of the most common transformations, used for positioning
23
+ graphics at specific locations.
24
+
25
+ === Syntax
26
+
27
+ [source,postscript]
28
+ ----
29
+ tx ty translate <1> <2> <3>
30
+ ----
31
+ <1> X-offset for translation (number)
32
+ <2> Y-offset for translation (number)
33
+ <3> Operator that applies translation
34
+
35
+ Where,
36
+
37
+ `tx`:: Translation in X direction (number)
38
+ `ty`:: Translation in Y direction (number)
39
+
40
+ Stack effect: `tx ty -- `
41
+
42
+ === Examples
43
+
44
+ [example]
45
+ ====
46
+ [source,postscript]
47
+ ----
48
+ 100 50 translate % Move origin to (100, 50)
49
+ newpath
50
+ 0 0 moveto % Now at (100, 50) in original space
51
+ 50 0 lineto % Line to (150, 50)
52
+ stroke
53
+ ----
54
+
55
+ After translation, (0, 0) refers to point (100, 50) in the original coordinate
56
+ system.
57
+ ====
58
+
59
+ [example]
60
+ ====
61
+ [source,postscript]
62
+ ----
63
+ gsave
64
+ 100 100 translate % Translate to (100, 100)
65
+ newpath
66
+ 0 0 50 0 360 arc % Circle at translated origin
67
+ fill
68
+ grestore
69
+
70
+ % Back to original origin
71
+ ----
72
+
73
+ Common pattern: translate, draw, then restore.
74
+ ====
75
+
76
+ [[scale]]
77
+ == scale
78
+
79
+ === General
80
+
81
+ The `scale` operator multiplies the user space units by specified scale
82
+ factors. This affects both coordinates and line widths.
83
+
84
+ Scaling with equal X and Y factors produces uniform scaling. Different factors
85
+ produce non-uniform (anisotropic) scaling.
86
+
87
+ === Syntax
88
+
89
+ [source,postscript]
90
+ ----
91
+ sx sy scale <1> <2> <3>
92
+ ----
93
+ <1> X-axis scale factor (number)
94
+ <2> Y-axis scale factor (number)
95
+ <3> Operator that applies scaling
96
+
97
+ Where,
98
+
99
+ `sx`:: Scale factor for X direction (number)
100
+ `sy`:: Scale factor for Y direction (number)
101
+
102
+ Stack effect: `sx sy -- `
103
+
104
+ === Examples
105
+
106
+ [example]
107
+ ====
108
+ [source,postscript]
109
+ ----
110
+ 2 2 scale % Double all dimensions
111
+ newpath
112
+ 50 50 moveto % Actually (100, 100)
113
+ 25 0 rlineto % Line of length 50 (2 × 25)
114
+ stroke
115
+ ----
116
+
117
+ After 2× scaling, all coordinates and dimensions are doubled.
118
+ ====
119
+
120
+ [example]
121
+ ====
122
+ [source,postscript]
123
+ ----
124
+ gsave
125
+ 2 1 scale % Stretch in X, not Y
126
+ newpath
127
+ 50 50 50 0 360 arc % Ellipse (100×50)
128
+ stroke
129
+ grestore
130
+ ----
131
+
132
+ Non-uniform scaling creates an ellipse from a circle.
133
+ ====
134
+
135
+ [example]
136
+ ====
137
+ [source,postscript]
138
+ ----
139
+ 72 72 scale % Scale to inches (72 points/inch)
140
+ newpath
141
+ 1 1 moveto % 1 inch from origin
142
+ 2 1 lineto % 1 inch line
143
+ stroke
144
+ ----
145
+
146
+ Scaling can convert units (e.g., inches to points).
147
+ ====
148
+
149
+ [[rotate]]
150
+ == rotate
151
+
152
+ === General
153
+
154
+ The `rotate` operator rotates the user coordinate system by the specified angle
155
+ (in degrees) around the current origin. Positive angles rotate counterclockwise.
156
+
157
+ Rotation affects both the coordinate axes and all subsequent drawing operations.
158
+
159
+ === Syntax
160
+
161
+ [source,postscript]
162
+ ----
163
+ angle rotate <1> <2>
164
+ ----
165
+ <1> Rotation angle in degrees (number)
166
+ <2> Operator that applies rotation
167
+
168
+ Where,
169
+
170
+ `angle`:: Rotation angle in degrees (number, positive=counterclockwise)
171
+
172
+ Stack effect: `angle -- `
173
+
174
+ === Examples
175
+
176
+ [example]
177
+ ====
178
+ [source,postscript]
179
+ ----
180
+ 45 rotate % Rotate 45° counterclockwise
181
+ newpath
182
+ 100 0 moveto % At 45° angle from origin
183
+ 50 0 rlineto
184
+ stroke
185
+ ----
186
+
187
+ After 45° rotation, the positive X-axis points northeast.
188
+ ====
189
+
190
+ [example]
191
+ ====
192
+ [source,postscript]
193
+ ----
194
+ gsave
195
+ 100 100 translate % Move to rotation center
196
+ 30 rotate % Rotate 30°
197
+ newpath
198
+ 0 0 moveto
199
+ 50 0 lineto % Rotated line from center
200
+ stroke
201
+ grestore
202
+ ----
203
+
204
+ Typical pattern: translate to rotation center, then rotate.
205
+ ====
206
+
207
+ [example]
208
+ ====
209
+ [source,postscript]
210
+ ----
211
+ % Draw 12 radial lines (like clock face)
212
+ 0 1 11 { % Loop 0 to 11
213
+ gsave
214
+ 100 100 translate % Center point
215
+ 30 mul rotate % Rotate by 0°, 30°, 60°, etc.
216
+ 0 0 moveto
217
+ 40 0 lineto
218
+ stroke
219
+ grestore
220
+ } for
221
+ ----
222
+
223
+ Multiple rotations create radial patterns.
224
+ ====
225
+
226
+ [[concat]]
227
+ == concat
228
+
229
+ === General
230
+
231
+ The `concat` operator concatenates (multiplies) an arbitrary matrix with the
232
+ current transformation matrix. This provides full control over transformations
233
+ beyond the basic translate/scale/rotate operations.
234
+
235
+ The matrix format is `[a b c d tx ty]` representing:
236
+
237
+ [source]
238
+ ----
239
+ [ a b 0 ]
240
+ [ c d 0 ]
241
+ [ tx ty 1 ]
242
+ ----
243
+
244
+ === Syntax
245
+
246
+ [source,postscript]
247
+ ----
248
+ [a b c d tx ty] concat <1> <2>
249
+ ----
250
+ <1> 6-element transformation matrix
251
+ <2> Operator that concatenates matrix
252
+
253
+ Where,
254
+
255
+ `a, b, c, d`:: Matrix coefficients for rotation/scaling/shearing
256
+ `tx, ty`:: Translation components
257
+
258
+ Stack effect: `matrix -- `
259
+
260
+ === Examples
261
+
262
+ [example]
263
+ ====
264
+ [source,postscript]
265
+ ----
266
+ % Identity matrix (no change)
267
+ [1 0 0 1 0 0] concat
268
+
269
+ % Translation by (100, 50)
270
+ [1 0 0 1 100 50] concat
271
+
272
+ % Scaling by 2× in both directions
273
+ [2 0 0 2 0 0] concat
274
+
275
+ % Rotation by 45° (approximately)
276
+ [0.707 0.707 -0.707 0.707 0 0] concat
277
+ ----
278
+
279
+ Matrix format enables precise control over transformations.
280
+ ====
281
+
282
+ [[currentmatrix]]
283
+ == currentmatrix
284
+
285
+ === General
286
+
287
+ The `currentmatrix` operator retrieves the current transformation matrix and
288
+ stores it in the provided matrix object.
289
+
290
+ This is useful for saving the current transformation state or examining the
291
+ cumulative effect of multiple transformations.
292
+
293
+ === Syntax
294
+
295
+ [source,postscript]
296
+ ----
297
+ matrix currentmatrix <1> <2>
298
+ ----
299
+ <1> Matrix object to receive CTM
300
+ <2> Operator that retrieves current matrix
301
+
302
+ Where,
303
+
304
+ `matrix`:: Matrix object (created with `matrix` operator)
305
+
306
+ Stack effect: `matrix -- matrix` (returns same matrix)
307
+
308
+ === Examples
309
+
310
+ [example]
311
+ ====
312
+ [source,postscript]
313
+ ----
314
+ matrix currentmatrix % Get current CTM
315
+ % Matrix now contains [a b c d tx ty]
316
+ ----
317
+
318
+ Returns the 6 coefficients of the current transformation.
319
+ ====
320
+
321
+ [[setmatrix]]
322
+ == setmatrix
323
+
324
+ === General
325
+
326
+ The `setmatrix` operator replaces the CTM with the specified matrix. Unlike
327
+ `concat`, which multiplies matrices, `setmatrix` completely replaces the CTM.
328
+
329
+ Use this with caution, as it bypasses the normal transformation accumulation.
330
+
331
+ === Syntax
332
+
333
+ [source,postscript]
334
+ ----
335
+ [a b c d tx ty] setmatrix <1> <2>
336
+ ----
337
+ <1> New transformation matrix
338
+ <2> Operator that replaces CTM
339
+
340
+ Where,
341
+
342
+ `matrix`:: 6-element matrix to use as new CTM
343
+
344
+ Stack effect: `matrix -- `
345
+
346
+ [[matrix]]
347
+ == matrix
348
+
349
+ === General
350
+
351
+ The `matrix` operator creates a new identity matrix object. This is typically
352
+ used with `currentmatrix` to capture the current transformation state.
353
+
354
+ === Syntax
355
+
356
+ [source,postscript]
357
+ ----
358
+ matrix <1>
359
+ ----
360
+ <1> Create identity matrix object
361
+
362
+ Where,
363
+
364
+ Stack effect: `-- matrix`
365
+
366
+ === Examples
367
+
368
+ [example]
369
+ ====
370
+ [source,postscript]
371
+ ----
372
+ /savedmatrix matrix def % Create matrix variable
373
+ savedmatrix currentmatrix pop % Save current CTM
374
+
375
+ % Make transformations
376
+ 100 100 translate
377
+ 45 rotate
378
+
379
+ % Restore saved transformation
380
+ savedmatrix setmatrix
381
+ ----
382
+
383
+ Save and restore transformation state.
384
+ ====
385
+
386
+ == Transformation Order
387
+
388
+ === General
389
+
390
+ Transformations are cumulative and apply in the order specified. The order
391
+ matters because matrix multiplication is not commutative.
392
+
393
+ === Order matters
394
+
395
+ [example]
396
+ ====
397
+ [source,postscript]
398
+ ----
399
+ % Pattern A: translate then rotate
400
+ gsave
401
+ 100 100 translate % Step 1
402
+ 45 rotate % Step 2
403
+ newpath
404
+ 0 0 moveto 50 0 lineto stroke
405
+ grestore
406
+
407
+ % Pattern B: rotate then translate
408
+ gsave
409
+ 45 rotate % Step 1
410
+ 100 100 translate % Step 2
411
+ newpath
412
+ 0 0 moveto 50 0 lineto stroke
413
+ grestore
414
+ ----
415
+
416
+ These produce different results: A rotates around point (100, 100), while B
417
+ rotates around the origin then translates the result.
418
+ ====
419
+
420
+ === Typical transformation sequence
421
+
422
+ [example]
423
+ ====
424
+ [source,postscript]
425
+ ----
426
+ gsave
427
+ % 1. Translate to desired position
428
+ xpos ypos translate
429
+
430
+ % 2. Rotate around that position
431
+ angle rotate
432
+
433
+ % 3. Scale if needed
434
+ sx sy scale
435
+
436
+ % 4. Draw in local coordinate system
437
+ % (0, 0) is now at (xpos, ypos), rotated and scaled
438
+ newpath
439
+ 0 0 moveto
440
+ width 0 lineto
441
+ stroke
442
+ grestore
443
+ ----
444
+
445
+ Standard pattern: translate, rotate, scale, then draw.
446
+ ====
447
+
448
+ == Coordinate System Inversion
449
+
450
+ === General
451
+
452
+ PostScript uses a coordinate system with Y increasing upward, while many
453
+ graphics systems (including SVG) use Y increasing downward. To convert between
454
+ them, use a reflection transformation.
455
+
456
+ [example]
457
+ ====
458
+ [source,postscript]
459
+ ----
460
+ % Reflect Y-axis for top-to-bottom coordinates
461
+ 1 -1 scale % Flip Y
462
+ 0 -height translate % Move origin to top
463
+
464
+ % Now (0, 0) is top-left, Y increases downward
465
+ ----
466
+
467
+ This transformation is commonly needed when converting PostScript to other
468
+ formats.
469
+ ====
470
+
471
+ == See Also
472
+
473
+ * link:graphics-state.adoc[Graphics State] - Transformations are part of
474
+ graphics state
475
+ * link:../graphics-model.adoc#coordinate-transformations[Coordinate
476
+ Transformations] - Conceptual overview
477
+ * link:../svg-mapping.adoc#transformation-matrix[SVG Mapping] - Converting to
478
+ SVG transforms
479
+ * link:index.adoc[Back to Operator Reference]