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.
- checksums.yaml +7 -0
- data/.rubocop.yml +19 -0
- data/.rubocop_todo.yml +141 -0
- data/Gemfile +15 -0
- data/LICENSE +25 -0
- data/README.adoc +473 -0
- data/Rakefile +10 -0
- data/docs/POSTSCRIPT.adoc +13 -0
- data/docs/postscript/fundamentals.adoc +356 -0
- data/docs/postscript/graphics-model.adoc +406 -0
- data/docs/postscript/implementation-notes.adoc +314 -0
- data/docs/postscript/index.adoc +153 -0
- data/docs/postscript/operators/arithmetic.adoc +461 -0
- data/docs/postscript/operators/control-flow.adoc +230 -0
- data/docs/postscript/operators/dictionary.adoc +191 -0
- data/docs/postscript/operators/graphics-state.adoc +528 -0
- data/docs/postscript/operators/index.adoc +288 -0
- data/docs/postscript/operators/painting.adoc +475 -0
- data/docs/postscript/operators/path-construction.adoc +553 -0
- data/docs/postscript/operators/stack-manipulation.adoc +374 -0
- data/docs/postscript/operators/transformations.adoc +479 -0
- data/docs/postscript/svg-mapping.adoc +369 -0
- data/exe/postsvg +6 -0
- data/lib/postsvg/cli.rb +103 -0
- data/lib/postsvg/colors.rb +33 -0
- data/lib/postsvg/converter.rb +214 -0
- data/lib/postsvg/errors.rb +11 -0
- data/lib/postsvg/graphics_state.rb +158 -0
- data/lib/postsvg/interpreter.rb +891 -0
- data/lib/postsvg/matrix.rb +106 -0
- data/lib/postsvg/parser/postscript_parser.rb +87 -0
- data/lib/postsvg/parser/transform.rb +21 -0
- data/lib/postsvg/parser.rb +18 -0
- data/lib/postsvg/path_builder.rb +101 -0
- data/lib/postsvg/svg_generator.rb +78 -0
- data/lib/postsvg/tokenizer.rb +161 -0
- data/lib/postsvg/version.rb +5 -0
- data/lib/postsvg.rb +78 -0
- data/postsvg.gemspec +38 -0
- data/scripts/regenerate_fixtures.rb +28 -0
- metadata +118 -0
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
= PostScript Language Fundamentals
|
|
2
|
+
|
|
3
|
+
== General
|
|
4
|
+
|
|
5
|
+
PostScript is a stack-based, interpreted programming language created by Adobe
|
|
6
|
+
Systems in 1984. It was designed as a page description language for printers
|
|
7
|
+
and imagesetters, but its capabilities extend to general-purpose programming.
|
|
8
|
+
|
|
9
|
+
The Postsvg library implements the graphics subset of PostScript necessary for
|
|
10
|
+
converting vector graphics to SVG format.
|
|
11
|
+
|
|
12
|
+
== Stack-Based Execution Model
|
|
13
|
+
|
|
14
|
+
=== General
|
|
15
|
+
|
|
16
|
+
PostScript uses a Last-In-First-Out (LIFO) stack called the operand stack to
|
|
17
|
+
hold data values. All operations in PostScript work by manipulating this stack.
|
|
18
|
+
|
|
19
|
+
When you execute a PostScript program, numbers and other literal values are
|
|
20
|
+
pushed onto the stack, and operators consume values from the stack and push
|
|
21
|
+
results back onto it.
|
|
22
|
+
|
|
23
|
+
=== Stack operations
|
|
24
|
+
|
|
25
|
+
[source,postscript]
|
|
26
|
+
----
|
|
27
|
+
5 % Push 5 onto stack → [5]
|
|
28
|
+
3 % Push 3 onto stack → [5 3]
|
|
29
|
+
add % Add: pop 3 and 5, push 8 → [8]
|
|
30
|
+
2 % Push 2 onto stack → [8 2]
|
|
31
|
+
mul % Multiply: pop 2 and 8, push 16 → [16]
|
|
32
|
+
----
|
|
33
|
+
|
|
34
|
+
Stack state notation: `[...]` shows stack contents, rightmost is top.
|
|
35
|
+
|
|
36
|
+
=== Stack visualization
|
|
37
|
+
|
|
38
|
+
[example]
|
|
39
|
+
====
|
|
40
|
+
[source]
|
|
41
|
+
----
|
|
42
|
+
Initial: []
|
|
43
|
+
10 [10]
|
|
44
|
+
20 [10 20]
|
|
45
|
+
30 [10 20 30]
|
|
46
|
+
add [10 50] % 20 + 30 = 50
|
|
47
|
+
mul [500] % 10 * 50 = 500
|
|
48
|
+
----
|
|
49
|
+
|
|
50
|
+
The final result (500) remains on the stack.
|
|
51
|
+
====
|
|
52
|
+
|
|
53
|
+
== Data Types
|
|
54
|
+
|
|
55
|
+
=== General
|
|
56
|
+
|
|
57
|
+
PostScript supports several data types, each serving specific purposes in
|
|
58
|
+
graphics programming.
|
|
59
|
+
|
|
60
|
+
[[numbers]]
|
|
61
|
+
=== Numbers
|
|
62
|
+
|
|
63
|
+
Numbers can be integers or real (floating-point) values.
|
|
64
|
+
|
|
65
|
+
Integers:: Whole numbers without a decimal point (e.g., `42`, `-7`, `0`)
|
|
66
|
+
Reals:: Numbers with decimal points (e.g., `3.14`, `-2.5`, `0.0`)
|
|
67
|
+
|
|
68
|
+
[example]
|
|
69
|
+
====
|
|
70
|
+
[source,postscript]
|
|
71
|
+
----
|
|
72
|
+
100 % Integer
|
|
73
|
+
72.5 % Real number
|
|
74
|
+
-3.14159 % Negative real
|
|
75
|
+
1.0e6 % Scientific notation (1,000,000)
|
|
76
|
+
----
|
|
77
|
+
====
|
|
78
|
+
|
|
79
|
+
[[strings]]
|
|
80
|
+
=== Strings
|
|
81
|
+
|
|
82
|
+
Strings are sequences of characters enclosed in parentheses.
|
|
83
|
+
|
|
84
|
+
[source,postscript]
|
|
85
|
+
----
|
|
86
|
+
(Hello, World!) % Simple string
|
|
87
|
+
(Line 1\nLine 2) % String with newline
|
|
88
|
+
(Parentheses \( \)) % Escaped parentheses
|
|
89
|
+
----
|
|
90
|
+
|
|
91
|
+
[[names]]
|
|
92
|
+
=== Names
|
|
93
|
+
|
|
94
|
+
Names are identifiers used to reference operators, variables, and procedures.
|
|
95
|
+
Literal names begin with a forward slash (`/`).
|
|
96
|
+
|
|
97
|
+
[source,postscript]
|
|
98
|
+
----
|
|
99
|
+
/MyVariable % Literal name
|
|
100
|
+
moveto % Executable name (operator)
|
|
101
|
+
/Times-Roman % Literal name for font
|
|
102
|
+
----
|
|
103
|
+
|
|
104
|
+
[[arrays]]
|
|
105
|
+
=== Arrays
|
|
106
|
+
|
|
107
|
+
Arrays are ordered collections of objects, enclosed in square brackets.
|
|
108
|
+
|
|
109
|
+
[source,postscript]
|
|
110
|
+
----
|
|
111
|
+
[1 2 3 4 5] % Array of numbers
|
|
112
|
+
[/name 100 (string)] % Mixed-type array
|
|
113
|
+
[1 2 add 3] % Array with executable operator
|
|
114
|
+
----
|
|
115
|
+
|
|
116
|
+
[[procedures]]
|
|
117
|
+
=== Procedures
|
|
118
|
+
|
|
119
|
+
Procedures are executable arrays enclosed in curly braces, used for defining
|
|
120
|
+
reusable code blocks.
|
|
121
|
+
|
|
122
|
+
[source,postscript]
|
|
123
|
+
----
|
|
124
|
+
{ 2 mul } % Procedure to double a number
|
|
125
|
+
{ 0 0 moveto 100 100 lineto stroke } % Drawing procedure
|
|
126
|
+
----
|
|
127
|
+
|
|
128
|
+
[[booleans]]
|
|
129
|
+
=== Booleans
|
|
130
|
+
|
|
131
|
+
Boolean values represent true or false.
|
|
132
|
+
|
|
133
|
+
[source,postscript]
|
|
134
|
+
----
|
|
135
|
+
true % Boolean true
|
|
136
|
+
false % Boolean false
|
|
137
|
+
----
|
|
138
|
+
|
|
139
|
+
== Coordinate System
|
|
140
|
+
|
|
141
|
+
=== General
|
|
142
|
+
|
|
143
|
+
PostScript uses a Cartesian coordinate system where:
|
|
144
|
+
|
|
145
|
+
* Origin (0, 0) is at the bottom-left corner
|
|
146
|
+
* X-axis increases to the right
|
|
147
|
+
* Y-axis increases upward
|
|
148
|
+
* Default unit is 1 point (1/72 inch)
|
|
149
|
+
|
|
150
|
+
=== Coordinate system diagram
|
|
151
|
+
|
|
152
|
+
[source]
|
|
153
|
+
----
|
|
154
|
+
+Y
|
|
155
|
+
↑
|
|
156
|
+
|
|
|
157
|
+
| (100, 100)
|
|
158
|
+
| •
|
|
159
|
+
|
|
|
160
|
+
|
|
|
161
|
+
| •
|
|
162
|
+
| (50, 50)
|
|
163
|
+
|
|
|
164
|
+
+---------------→ +X
|
|
165
|
+
(0, 0)
|
|
166
|
+
----
|
|
167
|
+
|
|
168
|
+
=== User space vs device space
|
|
169
|
+
|
|
170
|
+
User space:: The coordinate system used in PostScript programs
|
|
171
|
+
Device space:: The actual physical coordinates of the output device
|
|
172
|
+
|
|
173
|
+
Transformations convert between these spaces, allowing device-independent
|
|
174
|
+
graphics programming.
|
|
175
|
+
|
|
176
|
+
== Syntax Rules
|
|
177
|
+
|
|
178
|
+
=== General
|
|
179
|
+
|
|
180
|
+
PostScript syntax is designed to be simple and consistent.
|
|
181
|
+
|
|
182
|
+
=== Whitespace
|
|
183
|
+
|
|
184
|
+
Whitespace (spaces, tabs, newlines) separates tokens and is generally ignored.
|
|
185
|
+
|
|
186
|
+
[source,postscript]
|
|
187
|
+
----
|
|
188
|
+
10 20 add % Same as:
|
|
189
|
+
10
|
|
190
|
+
20
|
|
191
|
+
add
|
|
192
|
+
----
|
|
193
|
+
|
|
194
|
+
=== Comments
|
|
195
|
+
|
|
196
|
+
Comments begin with `%` and extend to the end of the line.
|
|
197
|
+
|
|
198
|
+
[source,postscript]
|
|
199
|
+
----
|
|
200
|
+
% This is a comment
|
|
201
|
+
100 100 moveto % Move to point (100, 100)
|
|
202
|
+
----
|
|
203
|
+
|
|
204
|
+
Special comments:
|
|
205
|
+
|
|
206
|
+
`%!PS-Adobe-3.0`:: Header identifying PostScript version
|
|
207
|
+
`%%BoundingBox: llx lly urx ury`:: Defines document bounding box
|
|
208
|
+
|
|
209
|
+
[example]
|
|
210
|
+
====
|
|
211
|
+
[source,postscript]
|
|
212
|
+
----
|
|
213
|
+
%!PS-Adobe-3.0 EPSF-3.0
|
|
214
|
+
%%BoundingBox: 0 0 612 792
|
|
215
|
+
%%Title: My Document
|
|
216
|
+
%%Creator: Postsvg Example
|
|
217
|
+
----
|
|
218
|
+
|
|
219
|
+
These structured comments provide metadata about the PostScript file.
|
|
220
|
+
====
|
|
221
|
+
|
|
222
|
+
=== Case sensitivity
|
|
223
|
+
|
|
224
|
+
PostScript is case-sensitive. `moveto`, `MoveTo`, and `MOVETO` are all
|
|
225
|
+
different names.
|
|
226
|
+
|
|
227
|
+
[source,postscript]
|
|
228
|
+
----
|
|
229
|
+
/MyName 100 def % Defines MyName
|
|
230
|
+
/myname 200 def % Defines different name: myname
|
|
231
|
+
----
|
|
232
|
+
|
|
233
|
+
=== Token delimiters
|
|
234
|
+
|
|
235
|
+
Tokens are delimited by:
|
|
236
|
+
|
|
237
|
+
* Whitespace (space, tab, newline)
|
|
238
|
+
* Special characters: `()`, `<>`, `[]`, `{}`, `%`, `/`
|
|
239
|
+
|
|
240
|
+
[source,postscript]
|
|
241
|
+
----
|
|
242
|
+
[1 2 3] % Array tokens: [ 1 2 3 ]
|
|
243
|
+
{2 mul} % Procedure tokens: { 2 mul }
|
|
244
|
+
/name 100 % Name token: /name followed by 100
|
|
245
|
+
----
|
|
246
|
+
|
|
247
|
+
== Execution Model
|
|
248
|
+
|
|
249
|
+
=== General
|
|
250
|
+
|
|
251
|
+
PostScript programs execute sequentially, processing tokens one at a time.
|
|
252
|
+
|
|
253
|
+
=== Literal vs executable objects
|
|
254
|
+
|
|
255
|
+
Literal objects:: Pushed directly onto the stack (numbers, literal names,
|
|
256
|
+
strings)
|
|
257
|
+
Executable objects:: Executed when encountered (operators, procedures)
|
|
258
|
+
|
|
259
|
+
[example]
|
|
260
|
+
====
|
|
261
|
+
[source,postscript]
|
|
262
|
+
----
|
|
263
|
+
100 % Literal: pushed to stack → [100]
|
|
264
|
+
/name % Literal name: pushed to stack → [100 /name]
|
|
265
|
+
dup % Executable: duplicates top stack item → [100 /name /name]
|
|
266
|
+
----
|
|
267
|
+
====
|
|
268
|
+
|
|
269
|
+
=== Immediate execution
|
|
270
|
+
|
|
271
|
+
[source,postscript]
|
|
272
|
+
----
|
|
273
|
+
5 3 add % Executes add immediately: [8]
|
|
274
|
+
{ 5 3 add } % Creates procedure, does not execute: [{ 5 3 add }]
|
|
275
|
+
exec % Executes procedure on stack: [8]
|
|
276
|
+
----
|
|
277
|
+
|
|
278
|
+
== Dictionaries and Scopes
|
|
279
|
+
|
|
280
|
+
=== General
|
|
281
|
+
|
|
282
|
+
Dictionaries are associative arrays that map keys to values. They implement
|
|
283
|
+
variable storage in PostScript.
|
|
284
|
+
|
|
285
|
+
=== Dictionary stack
|
|
286
|
+
|
|
287
|
+
PostScript maintains a dictionary stack separate from the operand stack.
|
|
288
|
+
Name lookup searches from the top of the dictionary stack downward.
|
|
289
|
+
|
|
290
|
+
=== Defining variables
|
|
291
|
+
|
|
292
|
+
[source,postscript]
|
|
293
|
+
----
|
|
294
|
+
/MyVar 100 def % Define MyVar with value 100
|
|
295
|
+
MyVar 2 mul % Use MyVar: [200]
|
|
296
|
+
----
|
|
297
|
+
|
|
298
|
+
The `def` operator stores a key-value pair in the current dictionary.
|
|
299
|
+
|
|
300
|
+
=== Local dictionaries
|
|
301
|
+
|
|
302
|
+
[source,postscript]
|
|
303
|
+
----
|
|
304
|
+
10 dict begin % Create and enter new dictionary
|
|
305
|
+
/x 100 def % Define x locally
|
|
306
|
+
/y 200 def % Define y locally
|
|
307
|
+
x y add % Use local variables: [300]
|
|
308
|
+
end % Exit dictionary
|
|
309
|
+
----
|
|
310
|
+
|
|
311
|
+
== Program Structure
|
|
312
|
+
|
|
313
|
+
=== General
|
|
314
|
+
|
|
315
|
+
A typical PostScript graphics program follows this structure:
|
|
316
|
+
|
|
317
|
+
[example]
|
|
318
|
+
====
|
|
319
|
+
[source,postscript]
|
|
320
|
+
----
|
|
321
|
+
%!PS-Adobe-3.0 EPSF-3.0
|
|
322
|
+
%%BoundingBox: 0 0 200 200
|
|
323
|
+
|
|
324
|
+
% Define any procedures or variables
|
|
325
|
+
/box { % Procedure to draw a box
|
|
326
|
+
newpath
|
|
327
|
+
0 0 moveto
|
|
328
|
+
100 0 lineto
|
|
329
|
+
100 100 lineto
|
|
330
|
+
0 100 lineto
|
|
331
|
+
closepath
|
|
332
|
+
} def
|
|
333
|
+
|
|
334
|
+
% Main graphics commands
|
|
335
|
+
gsave % Save state
|
|
336
|
+
50 50 translate % Position the box
|
|
337
|
+
box % Draw box outline
|
|
338
|
+
0.5 setgray % Set gray color
|
|
339
|
+
stroke % Render the outline
|
|
340
|
+
grestore % Restore state
|
|
341
|
+
|
|
342
|
+
showpage % Display the page
|
|
343
|
+
%%EOF
|
|
344
|
+
----
|
|
345
|
+
|
|
346
|
+
This example defines a reusable box procedure, positions it using
|
|
347
|
+
transformations, and renders it with specified styling.
|
|
348
|
+
====
|
|
349
|
+
|
|
350
|
+
== See Also
|
|
351
|
+
|
|
352
|
+
* link:graphics-model.adoc[Graphics Model] - Graphics state and paths
|
|
353
|
+
* link:operators/stack-manipulation.adoc[Stack Operators] - Stack
|
|
354
|
+
manipulation commands
|
|
355
|
+
* link:operators/dictionary.adoc[Dictionary Operators] - Dictionary operations
|
|
356
|
+
* link:index.adoc[Back to PostScript Quick Reference]
|