├── result └── TestPostscript.png ├── README.md ├── .gitignore ├── operators_misc.go ├── operators.go ├── procedure.go ├── operators_relational.go ├── samples_test.go ├── LICENSE.md ├── samples ├── test1.ps ├── 3dcolor.ps ├── Koch.ps ├── Mand.ps ├── grayalph.ps ├── snowflak.ps ├── colorcir.ps ├── maze.ps ├── escher.ps ├── vasarely.ps ├── grade.ps ├── golfer.ps └── manylines.ps ├── operators_control.go ├── operators_conflict.go ├── operators_stack.go ├── operators_array.go ├── operators_math.go ├── operators_dictionary.go ├── interpreter.go ├── operators_graphics.go └── scanner.go /result/TestPostscript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llgcode/ps/HEAD/result/TestPostscript.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ps 2 | 3 | [![Coverage](http://gocover.io/_badge/github.com/llgcode/ps?0)](http://gocover.io/github.com/llgcode/ps) 4 | [![GoDoc](https://godoc.org/github.com/llgcode/ps?status.svg)](https://godoc.org/github.com/llgcode/ps) 5 | 6 | Postscript interpreter written in go 7 | 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /operators_misc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The postscript-go Authors. All rights reserved. 2 | // created: 13/12/2010 by Laurent Le Goff 3 | 4 | // Miscellaneous Operators 5 | package ps 6 | 7 | //proc bind proc Replace operator names in proc with operators; perform idiom recognition 8 | func bind(interpreter *Interpreter) { 9 | pdef := interpreter.PopProcedureDefinition() 10 | values := make([]Value, len(pdef.Values)) 11 | for i, value := range pdef.Values { 12 | if s, ok := value.(string); ok { 13 | firstChar := s[0] 14 | if firstChar != '(' && firstChar != '/' { 15 | v, _ := interpreter.FindValueInDictionaries(s) 16 | operator, isOperator := v.(Operator) 17 | if v == nil { 18 | // log.Printf("Can't find def: %s\n", s) 19 | } 20 | if isOperator { 21 | values[i] = operator 22 | } else { 23 | values[i] = value 24 | } 25 | } else { 26 | values[i] = value 27 | } 28 | } else { 29 | values[i] = value 30 | } 31 | } 32 | pdef.Values = values 33 | interpreter.Push(pdef) 34 | } 35 | 36 | func initMiscellaneousOperators(interpreter *Interpreter) { 37 | interpreter.SystemDefine("bind", NewOperator(bind)) 38 | } 39 | -------------------------------------------------------------------------------- /operators.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The postscript-go Authors. All rights reserved. 2 | // created: 13/12/2010 by Laurent Le Goff 3 | 4 | package ps 5 | 6 | type OperatorFunc func(interpreter *Interpreter) 7 | 8 | type PrimitiveOperator struct { 9 | f OperatorFunc 10 | } 11 | 12 | func NewOperator(f OperatorFunc) *PrimitiveOperator { 13 | return &PrimitiveOperator{f} 14 | } 15 | 16 | func (o *PrimitiveOperator) Execute(interpreter *Interpreter) { 17 | o.f(interpreter) 18 | } 19 | 20 | func save(interpreter *Interpreter) { 21 | interpreter.Push("VM Snapshot") 22 | } 23 | 24 | func restore(interpreter *Interpreter) { 25 | interpreter.Pop() 26 | } 27 | 28 | func initSystemOperators(interpreter *Interpreter) { 29 | interpreter.SystemDefine("save", NewOperator(save)) 30 | interpreter.SystemDefine("restore", NewOperator(restore)) 31 | initStackOperator(interpreter) 32 | initMathOperators(interpreter) 33 | initArrayOperators(interpreter) 34 | initDictionaryOperators(interpreter) 35 | initRelationalOperators(interpreter) 36 | initControlOperators(interpreter) 37 | initMiscellaneousOperators(interpreter) 38 | initDrawingOperators(interpreter) 39 | 40 | initConflictingOperators(interpreter) 41 | } 42 | -------------------------------------------------------------------------------- /procedure.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The postscript-go Authors. All rights reserved. 2 | // created: 13/12/2010 by Laurent Le Goff 3 | 4 | package ps 5 | 6 | type ProcedureDefinition struct { 7 | Values []Value 8 | } 9 | 10 | func NewProcedureDefinition() *ProcedureDefinition { 11 | proceduredef := new(ProcedureDefinition) 12 | proceduredef.Values = make([]Value, 0, 100) 13 | return proceduredef 14 | } 15 | 16 | func (p *ProcedureDefinition) Add(value Value) { 17 | p.Values = append(p.Values, value) 18 | } 19 | 20 | type Procedure struct { 21 | def *ProcedureDefinition 22 | } 23 | 24 | func NewProcedure(def *ProcedureDefinition) *Procedure { 25 | return &Procedure{def} 26 | } 27 | 28 | func (p *Procedure) Execute(interpreter *Interpreter) { 29 | for _, value := range p.def.Values { 30 | if s, ok := value.(string); ok { 31 | firstChar := s[0] 32 | if firstChar != '(' && firstChar != '/' { 33 | interpreter.computeReference(s) 34 | } else { 35 | interpreter.Push(value) 36 | } 37 | } else { 38 | operator, isOperator := value.(Operator) 39 | if isOperator { 40 | operator.Execute(interpreter) 41 | } else { 42 | interpreter.Push(value) 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /operators_relational.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The postscript-go Authors. All rights reserved. 2 | // created: 13/12/2010 by Laurent Le Goff 3 | 4 | package ps 5 | 6 | func eq(interpreter *Interpreter) { 7 | value1 := interpreter.Pop() 8 | value2 := interpreter.Pop() 9 | interpreter.Push(value1 == value2) 10 | } 11 | 12 | func ne(interpreter *Interpreter) { 13 | value1 := interpreter.Pop() 14 | value2 := interpreter.Pop() 15 | interpreter.Push(value1 != value2) 16 | } 17 | 18 | func not(interpreter *Interpreter) { 19 | b := interpreter.PopBoolean() 20 | interpreter.Push(!b) 21 | } 22 | 23 | func lt(interpreter *Interpreter) { 24 | f2 := interpreter.PopFloat() 25 | f1 := interpreter.PopFloat() 26 | interpreter.Push(f1 < f2) 27 | } 28 | func gt(interpreter *Interpreter) { 29 | f2 := interpreter.PopFloat() 30 | f1 := interpreter.PopFloat() 31 | interpreter.Push(f1 > f2) 32 | } 33 | 34 | func initRelationalOperators(interpreter *Interpreter) { 35 | interpreter.SystemDefine("eq", NewOperator(eq)) 36 | interpreter.SystemDefine("ne", NewOperator(ne)) 37 | interpreter.SystemDefine("not", NewOperator(not)) 38 | interpreter.SystemDefine("lt", NewOperator(lt)) 39 | interpreter.SystemDefine("gt", NewOperator(gt)) 40 | } 41 | -------------------------------------------------------------------------------- /samples_test.go: -------------------------------------------------------------------------------- 1 | package ps 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "image" 7 | "image/png" 8 | "io/ioutil" 9 | "log" 10 | "os" 11 | "strings" 12 | "testing" 13 | 14 | "github.com/llgcode/draw2d/draw2dimg" 15 | ) 16 | 17 | func saveToPngFile(filePath string, m image.Image) { 18 | f, err := os.Create(filePath) 19 | if err != nil { 20 | log.Println(err) 21 | os.Exit(1) 22 | } 23 | defer f.Close() 24 | b := bufio.NewWriter(f) 25 | err = png.Encode(b, m) 26 | if err != nil { 27 | log.Println(err) 28 | os.Exit(1) 29 | } 30 | err = b.Flush() 31 | if err != nil { 32 | log.Println(err) 33 | os.Exit(1) 34 | } 35 | fmt.Printf("Wrote %s OK.\n", filePath) 36 | } 37 | 38 | func init() { 39 | os.Mkdir("result", 0666) 40 | } 41 | 42 | func TestTiger(t *testing.T) { 43 | i := image.NewRGBA(image.Rect(0, 0, 600, 800)) 44 | gc := draw2dimg.NewGraphicContext(i) 45 | gc.Translate(0, 380) 46 | gc.Scale(1, -1) 47 | gc.Translate(0, -380) 48 | src, err := os.OpenFile("samples/tiger.ps", 0, 0) 49 | if err != nil { 50 | return 51 | } 52 | defer src.Close() 53 | bytes, err := ioutil.ReadAll(src) 54 | reader := strings.NewReader(string(bytes)) 55 | interpreter := NewInterpreter(gc) 56 | interpreter.Execute(reader) 57 | saveToPngFile("result/TestPostscript.png", i) 58 | } 59 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Laurent Le Goff 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 10 | disclaimer in the documentation and/or other materials provided with the distribution. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 13 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 14 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 15 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 16 | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 17 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 18 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 19 | -------------------------------------------------------------------------------- /samples/test1.ps: -------------------------------------------------------------------------------- 1 | %! 2 | % Example of rotation... draws 36 lines in a circular pattern 3 | 4 | /box { 5 | newpath 6 | moveto 7 | 72 0 rlineto 8 | 0 72 rlineto 9 | -72 0 rlineto 10 | closepath 11 | } def 12 | 13 | % Specify font for text labels 14 | /Helvetica findfont 40 scalefont setfont 15 | 16 | gsave 17 | 40 40 translate % Set origin to (40, 40) 18 | 0 0 box stroke % Draw box at new origin... 19 | 77 0 moveto 20 | (Translated) show % and label 21 | grestore 22 | 23 | gsave 24 | 100 150 translate % Translate origin to (100, 150) 25 | 30 rotate % Rotate counter-clockwise by 30 degrees 26 | 0 0 box stroke % Draw box... 27 | 75 0 moveto 28 | (Translated & Rotated) show % and label 29 | grestore 30 | 31 | gsave 32 | 40 300 translate % Translate to (40, 300) 33 | 0.5 1 scale % Reduce x coord by 1/2, y coord left alone 34 | 0 0 box stroke % Draw box... 35 | 75 0 moveto 36 | (Translated & Squished) show % and label 37 | grestore 38 | 39 | gsave 40 | 300 300 translate % Set origin to (300, 300) 41 | 45 rotate % Rotate coordinates by 45 degrees 42 | 0.5 1 scale % Scale coordinates 43 | 0 0 box stroke % Draw box 44 | 75 0 moveto 45 | (Everything) show 46 | grestore 47 | 48 | showpage 49 | 50 | 51 | -------------------------------------------------------------------------------- /samples/3dcolor.ps: -------------------------------------------------------------------------------- 1 | %!PS 2 | /B {bind} bind def 3 | /D {def} def 4 | /Q {bind def} B D 5 | /E {exch def} Q 6 | /S {gsave} Q 7 | /R {grestore} Q 8 | /P 20 D 9 | /N P 1 sub D 10 | /I 1 P div D 11 | initclip clippath pathbbox newpath 12 | 72 sub /URy E 72 sub /URx E 72 add /LLy E 72 add /LLx E 13 | /Sq5 5 sqrt D 14 | /F 2 Sq5 add D 15 | /Wx URx LLx sub D /Wy URy LLy sub D 16 | /Xx Wx 4 div D /Xy Wy F div D /X Xx Xy le {Xx}{Xy}ifelse D 17 | Wx X 4 mul sub 2 div LLx add X 2 mul add Wy X F mul sub 2 div LLy add translate 18 | /X X Sq5 mul D 19 | X dup scale 20 | 0.1 X div setlinewidth 21 | S 22 | [ 1 .5 0 1 0 0 ] concat 23 | 0 1 N {I mul /A E 24 | 0 1 N {I mul /B E 25 | S A B translate 26 | newpath 0 0 moveto I 0 rlineto 0 I rlineto I neg 0 rlineto 27 | closepath 28 | S I B add 1 1 A sub setrgbcolor fill R stroke % Green 29 | R 30 | } for 31 | } for 32 | R 33 | S 34 | [ -1 .5 0 1 0 0 ] concat 35 | 0 1 N {I mul /A E 36 | 0 1 N {I mul /B E 37 | S A B translate 38 | newpath 0 0 moveto I 0 rlineto 0 I rlineto I neg 0 rlineto 39 | closepath 40 | S I B add 1 A sub 1 setrgbcolor fill R stroke % Blue 41 | R 42 | } for 43 | } for 44 | R 45 | S 46 | [ 1 .5 -1 0.5 0 1 ] concat 47 | 0 1 N {I mul /A E 48 | 0 1 N {I mul /B E 49 | S A B translate 50 | newpath 0 0 moveto I 0 rlineto 0 I rlineto I neg 0 rlineto 51 | closepath 52 | S 1 1 B sub 1 A sub setrgbcolor fill R stroke % Red 53 | R 54 | } for 55 | } for 56 | R 57 | showpage 58 | -------------------------------------------------------------------------------- /samples/Koch.ps: -------------------------------------------------------------------------------- 1 | %%% Start of L-system definition 2 | 3 | /STARTK { FK plusK plusK FK plusK plusK FK} def 4 | /FK { 5 | dup 0 eq 6 | { DK } % if the recursion order ends, draw forward 7 | { 8 | 1 sub % recurse 9 | 4 {dup} repeat % dup the number of parameters (order) needed. 10 | FK minusK FK plusK plusK FK minusK FK } 11 | ifelse 12 | pop % pop the dup'd order 13 | } bind def 14 | 15 | /angleK 60 def 16 | 17 | /minusK { % rotation to the right 18 | angleK neg rotate 19 | } bind def 20 | 21 | /plusK { % rotation to the left 22 | angleK rotate 23 | } bind def 24 | 25 | %%% End of L-System definition 26 | 27 | /DK { sizeK 3 orderK exp div 0 rlineto } bind def 28 | /thicknessK {1 orderK dup mul div} bind def 29 | 30 | %%% Scaling factors 31 | 32 | /orderK 3 def 33 | /sizeK 300 def 34 | 35 | %%% Draws a Koch's snowflake of radius 180 at 0 0 36 | 37 | /Koch180 { 38 | gsave 39 | newpath 40 | thicknessK setlinewidth 41 | 200 300 60 cos mul add 42 | neg 43 | 200 100 60 sin mul add 44 | neg 45 | translate 46 | 200 200 moveto 47 | orderK orderK orderK STARTK 48 | stroke 49 | closepath 50 | grestore 51 | } def % receives nothing 52 | 53 | %%% Draws an arbitrary Koch's snowflake 54 | 55 | /Koch { 56 | /orderK exch store 57 | gsave 58 | 3 1 roll 59 | translate 60 | 180 div dup scale 61 | rand 360 mod rotate 62 | Koch180 63 | grestore 64 | } def % Receives x y size order 65 | 66 | 67 | %%% Sample, bounded by an arc 68 | 69 | 400 400 100 3 Koch 70 | newpath 71 | 400 400 72 | 100 0 360 arc 73 | stroke 74 | closepath 75 | 76 | showpage -------------------------------------------------------------------------------- /samples/Mand.ps: -------------------------------------------------------------------------------- 1 | %!PS-Adobe-2.0 2 | 3 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | % % 5 | % Mandelbrot set via PostScript code. Not optimized % 6 | % in any way. Centered in A4 paper. Escape time, B&W % 7 | % % 8 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9 | 10 | /fun { 11 | 4 3 roll % y c1 c2 x 12 | dup dup % y c1 c2 x x x 13 | mul % y c1 c2 x x^2 14 | 5 4 roll % c1 c2 x x^2 y 15 | dup dup mul % c1 c2 x x^2 y y^2 16 | 2 index exch sub % c1 c2 x x^2 y (x^2-y^2) 17 | 6 1 roll 2 index % (x^2-y^2) c1 c2 x x^2 y x 18 | 2 mul mul % (x^2-y^2) c1 c2 x x^2 2xy 19 | 6 1 roll % 2xy (x^2-y^2) c1 c2 x x^2 20 | pop pop 4 1 roll % c2 2xy (x^2-y^2) c1 21 | dup 5 1 roll add % c1 c2 2xy (x^2-y^2+c1) 22 | 4 1 roll % (x^2-y^2+c1) c1 c2 2xy 23 | 1 index % (x^2-y^2+c1) c1 c2 2xy c2 24 | add 4 3 roll % c1 c2 (2xy+c2) (x^2-y^2+c1) 25 | exch 4 2 roll % (x^2-y^2+c1) (2xy+c2) c1 c2 26 | } def 27 | 28 | /res 500 def 29 | /iter 50 def 30 | 31 | 32 | 300 300 translate 33 | 90 rotate 34 | -150 -260 translate 35 | 0 1 res { 36 | /x exch def 37 | 0 1 res { 38 | /y exch def 39 | 0 0 40 | -2.5 4 x mul res div add 41 | 2 4 y mul res div sub 42 | iter -1 0 { 43 | /n exch store 44 | fun 45 | 2 index dup mul 46 | 4 index dup mul 47 | add sqrt 48 | 4 gt 49 | {exit} if 50 | } for 51 | pop pop pop pop 52 | 53 | 54 | n 0 gt 55 | {1 setgray 56 | x y 0.7 0 360 arc 57 | fill 58 | } 59 | { 60 | 0 setgray 61 | x y 0.5 0 360 arc 62 | fill 63 | } ifelse 64 | } for 65 | }for 66 | showpage 67 | 68 | -------------------------------------------------------------------------------- /samples/grayalph.ps: -------------------------------------------------------------------------------- 1 | %! 2 | % grayscaled text test, including a trivial user bitmap font 3 | 4 | /grayalphsave save def % prevent left over effects 5 | 6 | /inch {72 mul} def 7 | 8 | /BuildCharDict 10 dict def 9 | /$ExampleFont 7 dict def 10 | $ExampleFont begin 11 | /FontType 3 def % user defined font. 12 | /FontMatrix [1 0 0 1 0 0] def 13 | /FontBBox [0 0 1 1] def 14 | /Encoding 256 array def 15 | 0 1 255 {Encoding exch /.notdef put} for 16 | Encoding (a) 0 get /plus put 17 | /CharStrings 2 dict def 18 | CharStrings /.notdef {} put 19 | CharStrings /plus 20 | { gsave 21 | 0 0 moveto 22 | 32 32 true [32 0 0 -32 0 32] 23 | {<0007E000 0007E000 0007E000 0007E000 0007E000 0007E000 0007E000 0007E000 24 | 0007E000 0007E000 0007E000 0007E000 0007E000 FFFFFFFF FFFFFFFF FFFFFFFF 25 | FFFFFFFF FFFFFFFF FFFFFFFF 0007E000 0007E000 0007E000 0007E000 0007E000 26 | 0007E000 0007E000 0007E000 0007E000 0007E000 0007E000 0007E000 0007E000> 27 | } imagemask 28 | grestore 29 | } put 30 | /BuildChar 31 | { BuildCharDict begin 32 | /char exch def 33 | /fontdict exch def 34 | /charproc 35 | fontdict /Encoding get char get 36 | fontdict /CharStrings get 37 | exch get def 38 | 1 0 0 0 1 1 setcachedevice 39 | charproc 40 | end 41 | } def 42 | end 43 | 44 | /MyFont $ExampleFont definefont pop 45 | 46 | newpath 47 | .5 inch 7.5 inch moveto 48 | 7.5 inch 0 rlineto 49 | 0 1.5 inch rlineto 50 | -7.5 inch 0 rlineto 51 | closepath 52 | 0 setgray 53 | fill 54 | 55 | /MyFont findfont 72 scalefont setfont 56 | .75 inch 7.75 inch moveto 57 | 0 1 6 58 | { /n exch def 59 | 1 n 6 div sub setgray 60 | (a) show 61 | } for 62 | 63 | showpage 64 | clear cleardictstack 65 | grayalphsave restore 66 | -------------------------------------------------------------------------------- /samples/snowflak.ps: -------------------------------------------------------------------------------- 1 | %! 2 | %% Elizabeth D. Zwicky 3 | %% zwicky@erg.sri.com 4 | %% multiflake 5 | 6 | /newflake 7 | {/seed usertime def 8 | seed srand 9 | /strokecolor [rand 99 mod 100 div 10 | rand 99 mod 100 div 11 | 100 rand 22 mod sub 100 div] def 12 | /fillcolor [rand 99 mod 100 div 13 | 100 rand 22 mod sub 100 div 14 | rand 99 mod 100 div] def 15 | /eofillcolor [rand 99 mod 100 div 16 | rand 22 mod 100 div 17 | 100 rand 22 mod sub 100 div] def 18 | 19 | /colorfill {fillcolor aload pop setrgbcolor fill } def 20 | /colorstroke {strokecolor aload pop setrgbcolor stroke } def 21 | /eocolorfill {eofillcolor aload pop setrgbcolor eofill } def 22 | /arm {0 0 moveto 23 | 5 {3 {x y x y x y curveto} repeat} repeat 24 | seed srand 25 | 0 0 moveto 26 | 5 {3 {x neg y x neg y x neg y curveto} repeat} repeat 27 | seed srand 28 | } def 29 | 30 | newpath 31 | 32 | 0 0 moveto boxsize 0 rlineto 0 boxsize rlineto boxsize neg 0 rlineto 33 | 0 0 lineto 34 | 35 | rand 99 mod 100 div 36 | 100 rand 22 mod sub 100 div 37 | 100 rand 22 mod sub 100 div 38 | sethsbcolor fill 39 | seed srand 40 | boxsize 2 div boxsize 2 div translate 41 | 42 | %% If the device you are using can handle complex fills, replace the 43 | %% next three lines with: 44 | %% 45 | 6 {arm 60 rotate} repeat 46 | gsave colorfill grestore gsave eocolorfill grestore colorstroke 47 | %% 48 | %% This will be not only faster, but prettier. On a LaserWriter or a 49 | %% Tektronix Phaser II PS it gives a limitcheck. 50 | 51 | %% 6 {arm 60 rotate colorfill} repeat 52 | %% 6 {arm 60 rotate eocolorfill} repeat 53 | %% 6 {arm 60 rotate} repeat colorstroke 54 | } def 55 | 56 | 1 setlinewidth 57 | clippath [pathbbox]== pathbbox /ury exch def /urx exch def /lly exch def /llx exch def 58 | /minsize 250 def 59 | /pagewidth urx llx sub def 60 | /pageheight ury lly sub def 61 | /inwidth pagewidth minsize div def 62 | /inheight pageheight minsize div def 63 | 64 | /boxsize 65 | inwidth inheight gt 66 | {pagewidth inwidth truncate div} 67 | {pageheight inheight truncate div} 68 | ifelse 69 | def 70 | 71 | /inwidth pagewidth boxsize div cvi def 72 | /inheight pageheight boxsize div cvi def 73 | 74 | /x {rand 70 mod abs} def 75 | /y {rand 120 mod abs} def 76 | 77 | llx lly translate 78 | 79 | inheight dup == { 80 | inwidth { 81 | gsave 82 | (NEWFLAKE)== 83 | newflake 84 | grestore 85 | boxsize 0 translate 86 | } repeat 87 | boxsize inwidth mul neg boxsize translate 88 | } repeat 89 | 90 | 91 | showpage 92 | -------------------------------------------------------------------------------- /operators_control.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The postscript-go Authors. All rights reserved. 2 | // created: 13/12/2010 by Laurent Le Goff 3 | 4 | package ps 5 | 6 | import ( 7 | "log" 8 | ) 9 | 10 | // any exec – Execute arbitrary object 11 | func exec(interpreter *Interpreter) { 12 | value := interpreter.Pop() 13 | if pdef, ok := value.(*ProcedureDefinition); ok { 14 | NewProcedure(pdef).Execute(interpreter) 15 | } else if procedure, ok := value.(*Procedure); ok { 16 | procedure.Execute(interpreter) 17 | } else { 18 | log.Printf("Push value: %v\n", value) 19 | interpreter.Push(value) 20 | } 21 | } 22 | 23 | func ifoperator(interpreter *Interpreter) { 24 | operator := NewProcedure(interpreter.PopProcedureDefinition()) 25 | condition := interpreter.PopBoolean() 26 | if condition { 27 | operator.Execute(interpreter) 28 | } 29 | } 30 | 31 | func ifelse(interpreter *Interpreter) { 32 | operator2 := NewProcedure(interpreter.PopProcedureDefinition()) 33 | operator1 := NewProcedure(interpreter.PopProcedureDefinition()) 34 | condition := interpreter.PopBoolean() 35 | if condition { 36 | operator1.Execute(interpreter) 37 | } else { 38 | operator2.Execute(interpreter) 39 | } 40 | } 41 | 42 | func foroperator(interpreter *Interpreter) { 43 | proc := NewProcedure(interpreter.PopProcedureDefinition()) 44 | limit := interpreter.PopFloat() 45 | inc := interpreter.PopFloat() 46 | initial := interpreter.PopFloat() 47 | 48 | for i := initial; i <= limit; i += inc { 49 | interpreter.Push(i) 50 | proc.Execute(interpreter) 51 | } 52 | } 53 | 54 | func repeat(interpreter *Interpreter) { 55 | proc := NewProcedure(interpreter.PopProcedureDefinition()) 56 | times := interpreter.PopInt() 57 | for i := 0; i <= times; i++ { 58 | proc.Execute(interpreter) 59 | } 60 | } 61 | 62 | // any stopped bool -> Establish context for catching stop 63 | func stopped(interpreter *Interpreter) { 64 | value := interpreter.Pop() 65 | if pdef, ok := value.(*ProcedureDefinition); ok { 66 | NewProcedure(pdef).Execute(interpreter) 67 | } else { 68 | interpreter.Push(value) 69 | } 70 | interpreter.Push(false) 71 | } 72 | 73 | func initControlOperators(interpreter *Interpreter) { 74 | interpreter.SystemDefine("exec", NewOperator(exec)) 75 | interpreter.SystemDefine("if", NewOperator(ifoperator)) 76 | interpreter.SystemDefine("ifelse", NewOperator(ifelse)) 77 | interpreter.SystemDefine("for", NewOperator(foroperator)) 78 | interpreter.SystemDefine("repeat", NewOperator(repeat)) 79 | interpreter.SystemDefine("stopped", NewOperator(stopped)) 80 | } 81 | -------------------------------------------------------------------------------- /samples/colorcir.ps: -------------------------------------------------------------------------------- 1 | %! 2 | %/colorcirsave save def % prevent left over effects 3 | 4 | gsave 5 | /Times-Roman findfont 24 scalefont setfont 6 | 72 72 translate 0 0 moveto 1 0 0 setrgbcolor (Red) show 7 | 72 0 translate 0 0 moveto 0 1 0 setrgbcolor (Green) show 8 | 72 0 translate 0 0 moveto 0 0 1 setrgbcolor (Blue) show 9 | 72 0 translate 0 0 moveto 1 1 0 setrgbcolor (Yellow) show 10 | 72 0 translate 0 0 moveto 1 0 1 setrgbcolor (Pink) show 11 | 72 0 translate 0 0 moveto 0 1 1 setrgbcolor (Cyan) show 12 | 72 0 translate 0 0 moveto 0.9 0.9 0.9 setrgbcolor ('White') show 13 | grestore 14 | 15 | 0.0 setlinewidth 16 | 17 | /length 0.1 def 18 | /width 0.02 def 19 | /hsvcircle { 20 | gsave 21 | /h 0.0 def 22 | 0 4 360 { 23 | pop 24 | gsave 25 | 0.5 0.0 translate 26 | 27 | newpath 28 | 0.0 0.0 moveto 29 | length 0.0 lineto 30 | length width lineto 31 | 0.0 width lineto 32 | closepath 33 | h 1.0 1.0 sethsbcolor 34 | fill 35 | 36 | %newpath 37 | %0.0 0.0 moveto 38 | %length 0.0 lineto 39 | %length width lineto 40 | %0.0 width lineto 41 | %closepath 42 | %0.0 setgray 43 | %stroke 44 | 45 | grestore 46 | /h h 4 360 div add def 47 | 4 rotate 48 | } for 49 | grestore 50 | } def 51 | 52 | /graycircle { 53 | gsave 54 | /h -1.0 def 55 | 0 4 360 { 56 | pop 57 | gsave 58 | 0.5 0.0 translate 59 | 60 | newpath 61 | 0.0 0.0 moveto 62 | length 0.0 lineto 63 | length width lineto 64 | 0.0 width lineto 65 | closepath 66 | 67 | h abs setgray 68 | fill 69 | 70 | %newpath 71 | %0.0 0.0 moveto 72 | %length 0.0 lineto 73 | %length width lineto 74 | %0.0 width lineto 75 | %closepath 76 | %0.0 setgray 77 | %stroke 78 | grestore 79 | 80 | /h h 8 360 div add def 81 | 4 rotate 82 | } for 83 | grestore 84 | } def 85 | 86 | 0.0 setlinewidth 87 | 0.0 setgray 88 | 300 400 translate 89 | 500 500 scale 90 | 91 | 30 rotate 92 | 1.0 0.7 scale 93 | -30 rotate 94 | 95 | hsvcircle 96 | 0.8 0.8 scale 97 | graycircle 98 | 0.8 0.8 scale 99 | hsvcircle 100 | 0.8 0.8 scale 101 | graycircle 102 | 0.8 0.8 scale 103 | hsvcircle 104 | 0.8 0.8 scale 105 | graycircle 106 | 0.8 0.8 scale 107 | hsvcircle 108 | 0.8 0.8 scale 109 | graycircle 110 | 0.8 0.8 scale 111 | hsvcircle 112 | 0.8 0.8 scale 113 | graycircle 114 | 0.8 0.8 scale 115 | hsvcircle 116 | 0.8 0.8 scale 117 | graycircle 118 | 0.8 0.8 scale 119 | hsvcircle 120 | 0.8 0.8 scale 121 | graycircle 122 | 123 | showpage 124 | %clear cleardictstack 125 | %colorcirsave restore 126 | -------------------------------------------------------------------------------- /operators_conflict.go: -------------------------------------------------------------------------------- 1 | package ps 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | ) 7 | 8 | // dictionary copy conflict with stack copy 9 | // type dicriminant 10 | func commonCopy(interpreter *Interpreter) { 11 | switch v := interpreter.Peek().(type) { 12 | case float64: 13 | copystack(interpreter) 14 | case Dictionary: 15 | copydict(interpreter) 16 | default: 17 | panic(fmt.Sprintf("Not yet implemented: %v copy", v)) 18 | } 19 | } 20 | func commonforall(interpreter *Interpreter) { 21 | switch v := interpreter.Get(1).(type) { 22 | case Dictionary: 23 | foralldict(interpreter) 24 | case []Value: 25 | forallarray(interpreter) 26 | case string: 27 | panic("Not yet implemented: string proc forall") 28 | default: 29 | panic(fmt.Sprintf("Not yet implemented: %v proc forall", v)) 30 | } 31 | } 32 | 33 | func length(interpreter *Interpreter) { 34 | switch v := interpreter.Peek().(type) { 35 | case Dictionary: 36 | lengthdict(interpreter) 37 | case []Value: 38 | lengtharray(interpreter) 39 | case string: 40 | panic("Not yet implemented: string proc forall") 41 | default: 42 | panic(fmt.Sprintf("Not yet implemented: %v length", v)) 43 | } 44 | } 45 | func get(interpreter *Interpreter) { 46 | switch v := interpreter.Get(1).(type) { 47 | case Dictionary: 48 | getdict(interpreter) 49 | case []Value: 50 | getarray(interpreter) 51 | case string: 52 | panic("Not yet implemented: string proc forall") 53 | default: 54 | panic(fmt.Sprintf("Not yet implemented: %v index get", v)) 55 | } 56 | } 57 | func put(interpreter *Interpreter) { 58 | switch v := interpreter.Get(2).(type) { 59 | case Dictionary: 60 | putdict(interpreter) 61 | case []Value: 62 | putarray(interpreter) 63 | case string: 64 | panic("Not yet implemented: string proc forall") 65 | default: 66 | panic(fmt.Sprintf("Not yet implemented: %v index any put", v)) 67 | } 68 | } 69 | 70 | func readonly(interpreter *Interpreter) { 71 | log.Println("readonly, not yet implemented") 72 | } 73 | 74 | func cvlit(interpreter *Interpreter) { 75 | log.Println("cvlit, not yet implemented") 76 | } 77 | 78 | func xcheck(interpreter *Interpreter) { 79 | value := interpreter.Pop() 80 | if _, ok := value.(*ProcedureDefinition); ok { 81 | interpreter.Push(true) 82 | } else { 83 | interpreter.Push(false) 84 | } 85 | } 86 | 87 | func initConflictingOperators(interpreter *Interpreter) { 88 | interpreter.SystemDefine("copy", NewOperator(commonCopy)) 89 | interpreter.SystemDefine("forall", NewOperator(commonforall)) 90 | interpreter.SystemDefine("length", NewOperator(length)) 91 | interpreter.SystemDefine("get", NewOperator(get)) 92 | interpreter.SystemDefine("put", NewOperator(put)) 93 | interpreter.SystemDefine("readonly", NewOperator(readonly)) 94 | interpreter.SystemDefine("cvlit", NewOperator(cvlit)) 95 | interpreter.SystemDefine("xcheck", NewOperator(xcheck)) 96 | } 97 | -------------------------------------------------------------------------------- /operators_stack.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The postscript-go Authors. All rights reserved. 2 | // created: 13/12/2010 by Laurent Le Goff 3 | 4 | //Operand Stack Manipulation Operators 5 | package ps 6 | 7 | //any pop – -> Discard top element 8 | func pop(interpreter *Interpreter) { 9 | interpreter.Pop() 10 | } 11 | 12 | //any1 any2 exch any2 any1 -> Exchange top two elements 13 | func exch(interpreter *Interpreter) { 14 | value1 := interpreter.Pop() 15 | value2 := interpreter.Pop() 16 | interpreter.Push(value1) 17 | interpreter.Push(value2) 18 | } 19 | 20 | //any dup any any -> Duplicate top element 21 | func dup(interpreter *Interpreter) { 22 | interpreter.Push(interpreter.Peek()) 23 | } 24 | 25 | //any1 … anyn n copy any1 … anyn any1 … anyn -> Duplicate top n elements 26 | func copystack(interpreter *Interpreter) { 27 | n := interpreter.PopInt() 28 | values := interpreter.GetValues(n) 29 | for _, value := range values { 30 | interpreter.Push(value) 31 | } 32 | } 33 | 34 | //anyn … any0 n index anyn … any0 anyn -> Duplicate arbitrary element 35 | func index(interpreter *Interpreter) { 36 | f := interpreter.PopInt() 37 | interpreter.Push(interpreter.Get(int(f))) 38 | } 39 | 40 | //anyn−1 … any0 n j roll any(j−1) mod n … any0 anyn−1 … anyj mod n -> Roll n elements up j times 41 | func roll(interpreter *Interpreter) { 42 | j := interpreter.PopInt() 43 | n := interpreter.PopInt() 44 | values := interpreter.PopValues(n) 45 | j %= n 46 | for i := 0; i < n; i++ { 47 | interpreter.Push(values[(n+i-j)%n]) 48 | } 49 | } 50 | 51 | //any1 … anyn clear -> Discard all elements 52 | func clear(interpreter *Interpreter) { 53 | interpreter.ClearOperands() 54 | } 55 | 56 | //any1 … anyn count any1 … anyn n -> Count elements on stack 57 | func count(interpreter *Interpreter) { 58 | interpreter.Push(interpreter.OperandSize()) 59 | } 60 | 61 | //Mark 62 | type Mark struct{} 63 | 64 | //– mark mark -> Push mark on stack 65 | func mark(interpreter *Interpreter) { 66 | interpreter.Push(Mark{}) 67 | } 68 | 69 | //mark obj 1 … obj n cleartomark – -> Discard elements down through mark 70 | func cleartomark(interpreter *Interpreter) { 71 | value := interpreter.Pop() 72 | for _, ok := value.(Mark); !ok; { 73 | value = interpreter.Pop() 74 | } 75 | } 76 | 77 | //mark obj 1 … obj n counttomark mark obj 1 … obj n n -> Count elements down to mark 78 | func counttomark(interpreter *Interpreter) { 79 | i := 0 80 | value := interpreter.Get(i) 81 | for _, ok := value.(Mark); !ok; i++ { 82 | value = interpreter.Get(i) 83 | } 84 | interpreter.Push(float64(i)) 85 | } 86 | 87 | func initStackOperator(interpreter *Interpreter) { 88 | interpreter.SystemDefine("pop", NewOperator(pop)) 89 | interpreter.SystemDefine("exch", NewOperator(exch)) 90 | interpreter.SystemDefine("dup", NewOperator(dup)) 91 | interpreter.SystemDefine("index", NewOperator(index)) 92 | interpreter.SystemDefine("roll", NewOperator(roll)) 93 | interpreter.SystemDefine("clear", NewOperator(clear)) 94 | interpreter.SystemDefine("count", NewOperator(count)) 95 | interpreter.SystemDefine("mark", NewOperator(mark)) 96 | interpreter.SystemDefine("cleartomark", NewOperator(mark)) 97 | interpreter.SystemDefine("counttomark", NewOperator(mark)) 98 | } 99 | -------------------------------------------------------------------------------- /operators_array.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The postscript-go Authors. All rights reserved. 2 | // created: 13/12/2010 by Laurent Le Goff 3 | 4 | package ps 5 | 6 | //int array array -> Create array of length int 7 | func array(interpreter *Interpreter) { 8 | interpreter.Push(make([]Value, interpreter.PopInt())) 9 | } 10 | 11 | //array length int -> Return number of elements in array 12 | func lengtharray(interpreter *Interpreter) { 13 | interpreter.Push(float64(len(interpreter.Pop().([]Value)))) 14 | } 15 | 16 | //array index get any -> Return array element indexed by index 17 | func getarray(interpreter *Interpreter) { 18 | index := interpreter.PopInt() 19 | array := interpreter.Pop().([]Value) 20 | interpreter.Push(array[index]) 21 | } 22 | 23 | //array index any put – -> Put any into array at index 24 | func putarray(interpreter *Interpreter) { 25 | value := interpreter.Pop() 26 | index := interpreter.PopInt() 27 | array := interpreter.Pop().([]Value) 28 | array[index] = value 29 | } 30 | 31 | //array index count getinterval subarray -> Return subarray of array starting at index for count elements 32 | func getinterval(interpreter *Interpreter) { 33 | count := interpreter.PopInt() 34 | index := interpreter.PopInt() 35 | array := interpreter.Pop().([]Value) 36 | subarray := make([]Value, count) 37 | copy(subarray, array[index:index+count]) 38 | interpreter.Push(subarray) 39 | } 40 | 41 | //array1 index array2 putinterval – Replace subarray of array1 starting at index by array2|packedarray2 42 | func putinterval(interpreter *Interpreter) { 43 | array2 := interpreter.Pop().([]Value) 44 | index := interpreter.PopInt() 45 | array1 := interpreter.Pop().([]Value) 46 | for i, v := range array2 { 47 | array1[i+index] = v 48 | } 49 | } 50 | 51 | // any0 … anyn−1 array astore array 52 | // stores the objects any0 to anyn−1 from the operand stack into array, where n is the length of array 53 | func astore(interpreter *Interpreter) { 54 | array := interpreter.Pop().([]Value) 55 | n := len(array) 56 | for i := 0; i < n; i++ { 57 | array[i] = interpreter.Pop() 58 | } 59 | } 60 | 61 | //array aload any0 … any-1 array 62 | //Push all elements of array on stack 63 | func aload(interpreter *Interpreter) { 64 | array := interpreter.Pop().([]Value) 65 | for _, v := range array { 66 | interpreter.Push(v) 67 | } 68 | interpreter.Push(array) 69 | } 70 | 71 | //array proc forall – Execute proc for each element of array 72 | func forallarray(interpreter *Interpreter) { 73 | proc := NewProcedure(interpreter.PopProcedureDefinition()) 74 | array := interpreter.Pop().([]Value) 75 | for _, v := range array { 76 | interpreter.Push(v) 77 | proc.Execute(interpreter) 78 | } 79 | } 80 | 81 | var packing bool = false 82 | 83 | func currentpacking(interpreter *Interpreter) { 84 | interpreter.Push(packing) 85 | } 86 | func setpacking(interpreter *Interpreter) { 87 | packing = interpreter.PopBoolean() 88 | } 89 | 90 | func initArrayOperators(interpreter *Interpreter) { 91 | interpreter.SystemDefine("array", NewOperator(array)) 92 | interpreter.SystemDefine("getinterval", NewOperator(getinterval)) 93 | interpreter.SystemDefine("putinterval", NewOperator(putinterval)) 94 | interpreter.SystemDefine("astore", NewOperator(astore)) 95 | interpreter.SystemDefine("aload", NewOperator(aload)) 96 | interpreter.SystemDefine("currentpacking", NewOperator(currentpacking)) 97 | interpreter.SystemDefine("setpacking", NewOperator(setpacking)) 98 | 99 | } 100 | -------------------------------------------------------------------------------- /operators_math.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The postscript-go Authors. All rights reserved. 2 | // created: 13/12/2010 by Laurent Le Goff 3 | 4 | //Arithmetic and Math Operators 5 | package ps 6 | 7 | import ( 8 | "math" 9 | "math/rand" 10 | ) 11 | 12 | // begin Primitive Operator implementation 13 | 14 | //num1 num2 add sum -> Return num1 plus num2 15 | func add(interpreter *Interpreter) { 16 | num2 := interpreter.PopFloat() 17 | num1 := interpreter.PopFloat() 18 | interpreter.Push(num1 + num2) 19 | } 20 | 21 | //num1 num2 div quotient -> Return num1 divided by num2 22 | func div(interpreter *Interpreter) { 23 | num2 := interpreter.PopFloat() 24 | num1 := interpreter.PopFloat() 25 | interpreter.Push(num1 / num2) 26 | } 27 | 28 | //int1 int2 idiv quotient -> Return int1 divided by int2 29 | func idiv(interpreter *Interpreter) { 30 | int2 := interpreter.PopInt() 31 | int1 := interpreter.PopInt() 32 | interpreter.Push(float64(int1 / int2)) 33 | } 34 | 35 | //int int mod remainder -> Return remainder after dividing int by int 36 | func mod(interpreter *Interpreter) { 37 | int2 := interpreter.PopInt() 38 | int1 := interpreter.PopInt() 39 | interpreter.Push(float64(int1 % int2)) 40 | } 41 | 42 | //num1 num2 mul product -> Return num1 times num2 43 | func mul(interpreter *Interpreter) { 44 | num2 := interpreter.PopFloat() 45 | num1 := interpreter.PopFloat() 46 | interpreter.Push(num1 * num2) 47 | } 48 | 49 | //num1 num2 sub difference -> Return num1 minus num2 50 | func sub(interpreter *Interpreter) { 51 | num2 := interpreter.PopFloat() 52 | num1 := interpreter.PopFloat() 53 | interpreter.Push(num1 - num2) 54 | } 55 | 56 | //num1 abs num2 -> Return absolute value of num1 57 | func abs(interpreter *Interpreter) { 58 | f := interpreter.PopFloat() 59 | interpreter.Push(math.Abs(f)) 60 | } 61 | 62 | //num1 neg num2 -> Return negative of num1 63 | func neg(interpreter *Interpreter) { 64 | f := interpreter.PopFloat() 65 | interpreter.Push(-f) 66 | } 67 | 68 | //num1 ceiling num2 -> Return ceiling of num1 69 | func ceiling(interpreter *Interpreter) { 70 | f := interpreter.PopFloat() 71 | interpreter.Push(float64(int(f + 1))) 72 | } 73 | 74 | //num1 floor num2 -> Return floor of num1 75 | func floor(interpreter *Interpreter) { 76 | f := interpreter.PopFloat() 77 | interpreter.Push(math.Floor(f)) 78 | } 79 | 80 | //num1 round num2 -> Round num1 to nearest integer 81 | func round(interpreter *Interpreter) { 82 | f := interpreter.PopFloat() 83 | interpreter.Push(float64(int(f + 0.5))) 84 | } 85 | 86 | //num1 truncate num2 -> Remove fractional part of num1 87 | func truncate(interpreter *Interpreter) { 88 | f := interpreter.PopFloat() 89 | interpreter.Push(float64(int(f))) 90 | } 91 | 92 | //num sqrt real -> Return square root of num 93 | func sqrt(interpreter *Interpreter) { 94 | f := interpreter.PopFloat() 95 | interpreter.Push(float64(math.Sqrt(f))) 96 | } 97 | 98 | //num den atan angle -> Return arctangent of num/den in degrees 99 | func atan(interpreter *Interpreter) { 100 | den := interpreter.PopFloat() 101 | num := interpreter.PopFloat() 102 | interpreter.Push(math.Atan2(num, den) * (180.0 / math.Pi)) 103 | } 104 | 105 | //angle cos real -> Return cosine of angle degrees 106 | func cos(interpreter *Interpreter) { 107 | a := interpreter.PopFloat() * math.Pi / 180 108 | interpreter.Push(math.Cos(a)) 109 | } 110 | 111 | //angle sin real -> Return sine of angle degrees 112 | func sin(interpreter *Interpreter) { 113 | a := interpreter.PopFloat() * math.Pi / 180 114 | interpreter.Push(math.Sin(a)) 115 | } 116 | 117 | //base exponent exp real -> Raise base to exponent power 118 | func exp(interpreter *Interpreter) { 119 | exponent := interpreter.PopFloat() 120 | base := interpreter.PopFloat() 121 | interpreter.Push(math.Pow(base, exponent)) 122 | } 123 | 124 | //num ln real -> Return natural logarithm (base e) 125 | func ln(interpreter *Interpreter) { 126 | num := interpreter.PopFloat() 127 | interpreter.Push(math.Log(num)) 128 | } 129 | 130 | //num log real -> Return common logarithm (base 10) 131 | func log10(interpreter *Interpreter) { 132 | num := interpreter.PopFloat() 133 | interpreter.Push(math.Log10(num)) 134 | } 135 | 136 | //– rand int Generate pseudo-random integer 137 | func randInt(interpreter *Interpreter) { 138 | interpreter.Push(float64(rand.Int())) 139 | } 140 | 141 | var randGenerator *rand.Rand 142 | 143 | //int srand – -> Set random number seed 144 | func srand(interpreter *Interpreter) { 145 | randGenerator = rand.New(rand.NewSource(int64(interpreter.PopInt()))) 146 | } 147 | 148 | //– rrand int -> Return random number seed 149 | func rrand(interpreter *Interpreter) { 150 | interpreter.Push(float64(randGenerator.Int())) 151 | } 152 | 153 | func initMathOperators(interpreter *Interpreter) { 154 | interpreter.SystemDefine("add", NewOperator(add)) 155 | interpreter.SystemDefine("div", NewOperator(div)) 156 | interpreter.SystemDefine("idiv", NewOperator(idiv)) 157 | interpreter.SystemDefine("mod", NewOperator(mod)) 158 | interpreter.SystemDefine("mul", NewOperator(mul)) 159 | interpreter.SystemDefine("sub", NewOperator(sub)) 160 | interpreter.SystemDefine("abs", NewOperator(abs)) 161 | interpreter.SystemDefine("neg", NewOperator(neg)) 162 | interpreter.SystemDefine("ceiling", NewOperator(ceiling)) 163 | interpreter.SystemDefine("floor", NewOperator(floor)) 164 | interpreter.SystemDefine("round", NewOperator(round)) 165 | interpreter.SystemDefine("truncate", NewOperator(truncate)) 166 | interpreter.SystemDefine("sqrt", NewOperator(sqrt)) 167 | interpreter.SystemDefine("atan", NewOperator(atan)) 168 | interpreter.SystemDefine("cos", NewOperator(cos)) 169 | interpreter.SystemDefine("sin", NewOperator(sin)) 170 | interpreter.SystemDefine("exp", NewOperator(exp)) 171 | interpreter.SystemDefine("ln", NewOperator(ln)) 172 | interpreter.SystemDefine("log", NewOperator(log10)) 173 | interpreter.SystemDefine("rand", NewOperator(randInt)) 174 | interpreter.SystemDefine("srand", NewOperator(srand)) 175 | interpreter.SystemDefine("rrand", NewOperator(rrand)) 176 | 177 | } 178 | -------------------------------------------------------------------------------- /samples/maze.ps: -------------------------------------------------------------------------------- 1 | %!PS 2 | %%Pages: 1 3 | %%EndComments 4 | 5 | % Yet Another Maze Maker 6 | % Version 2 7 | % Written by Peter Sorotokin, 1996-1998 8 | % This program is in the public domain. 9 | 10 | % Note: do not send this job to the printer until you know 11 | % how to cancel it (it may take a LOT of time on slow printer; 12 | % it takes couple minutes on my LaserJet 4). 13 | 14 | %%BeginSetup 15 | 16 | % put your sizes here: 17 | 18 | /width 25 def 19 | /height 25 def 20 | 21 | % seed number here: 22 | 23 | 0 srand % put your seed number instead of 0 (normally not required) 24 | systemdict /realtime known { realtime srand } if 25 | 26 | % initialization 27 | 28 | /size width height mul def 29 | /zone size array def 30 | /zsize size array def 31 | /vert width 1 add array def 32 | /hor height 1 add array def 33 | 34 | /w1 width 1 sub def 35 | /h1 height 1 sub def 36 | 37 | 0 1 size 1 sub { dup zsize exch 1 put zone exch dup put } bind for 38 | 0 1 width { vert exch height string 0 1 h1 39 | { 1 index exch 255 put } for put } bind for 40 | 0 1 height { hor exch width string 0 1 w1 41 | { 1 index exch 255 put } for put } bind for 42 | 43 | % define subroutines 44 | 45 | /db { dup 20 string cvs = } bind def 46 | 47 | /find_set { { zone 1 index get dup 3 1 roll eq {exit} if } loop} bind def 48 | 49 | /merge_sets { 50 | 2 copy zsize exch get 51 | exch zsize exch get 2 copy gt 52 | 3 1 roll add exch 53 | { zsize 2 index 3 -1 roll put 54 | zone 3 1 roll put } 55 | { zsize 3 index 3 -1 roll put 56 | zone 3 1 roll exch put } 57 | ifelse } bind def 58 | 59 | %%EndSetup 60 | 61 | %%Page: maze 1 62 | 63 | % building 64 | 65 | size 1 sub 66 | { 67 | { 68 | rand 2 mod 0 eq 69 | { 70 | rand height mod 71 | rand w1 mod 2 copy 72 | height mul add 73 | dup height add 74 | find_set exch find_set 75 | 2 copy eq 76 | { 77 | pop pop pop pop 78 | } 79 | { 80 | merge_sets vert exch 1 add get exch 0 put exit 81 | } 82 | ifelse 83 | } 84 | { 85 | rand h1 mod 86 | rand width mod 2 copy 87 | height mul add 88 | dup 1 add 89 | find_set exch find_set 90 | 2 copy eq 91 | { 92 | pop pop pop pop 93 | } 94 | { 95 | merge_sets exch hor exch 1 add get exch 0 put exit 96 | } 97 | ifelse 98 | } 99 | ifelse 100 | } 101 | loop 102 | } bind repeat 103 | 104 | % make entrance and exit 105 | 106 | vert 0 get rand height mod 0 put 107 | vert width get rand height mod 0 put 108 | 109 | % setup output 110 | 111 | clippath pathbbox 112 | 2 index sub exch 113 | 3 index sub exch 114 | 4 2 roll translate 115 | 2 copy height 4 add div exch width 4 add div 116 | 2 copy gt {exch} if pop /myscale exch def 117 | 118 | myscale height mul sub 2 div exch 119 | myscale width mul sub 2 div exch 120 | translate 121 | 122 | myscale myscale scale 123 | 0.05 setlinewidth 124 | 125 | newpath 126 | 127 | % render the maze 128 | 129 | 0 1 width { dup 0 moveto vert exch get 0 1 height 1 sub 130 | { 1 index exch get 0 eq 0 1 3 -1 roll { rmoveto } { rlineto } ifelse } 131 | for pop } bind for 132 | 133 | 0 1 height { dup 0 exch moveto hor exch get 0 1 width 1 sub 134 | { 1 index exch get 0 eq 1 0 3 -1 roll { rmoveto } { rlineto } ifelse } 135 | for pop } bind for 136 | 137 | stroke 138 | 139 | stroke 140 | 141 | % Quick hack to solve the maze. 142 | % This part written by Christian Lehner. 143 | 144 | clear 145 | 146 | /NORTH 1 def 147 | /WEST 2 def 148 | /SOUTH 4 def 149 | /EAST 8 def 150 | /CRUMB 16 def 151 | 152 | /find_door {% column => index 153 | dup 0 1 3 -1 roll length 1 sub { 154 | 2 copy get 0 eq { 155 | exch pop 156 | exit 157 | } { 158 | pop 159 | } ifelse 160 | } for 161 | } bind def 162 | 163 | /mentrance vert 0 get find_door def 164 | /mexit vert width get find_door def 165 | 166 | /maze [height {[width {0} repeat]} repeat] def 167 | 168 | /mget {% row col => int 169 | maze 3 -1 roll get exch get 170 | } bind def 171 | 172 | /mset {% row col int => - 173 | maze 4 -1 roll get 3 -2 roll put 174 | } bind def 175 | 176 | /initmaze { 177 | 0 1 height 1 sub {/row exch def 178 | /mrow maze row get def 179 | 0 1 width 1 sub {/col exch def 180 | % north 181 | hor row 1 add get col get 0 eq { 182 | mrow col 2 copy get //NORTH or put 183 | } if 184 | % west 185 | vert col get row get 0 eq { 186 | mrow col 2 copy get //WEST or put 187 | } if 188 | % south 189 | hor row get col get 0 eq { 190 | mrow col 2 copy get //SOUTH or put 191 | } if 192 | % east 193 | vert col 1 add get row get 0 eq { 194 | mrow col 2 copy get //EAST or put 195 | } if 196 | } for 197 | } for 198 | } bind def 199 | 200 | /step {% row col side => row' col' 201 | /side exch def 202 | /col exch def 203 | /row exch def 204 | side //NORTH eq { 205 | row 1 add col 206 | } { 207 | side //WEST eq { 208 | row col 1 sub 209 | } { 210 | side //SOUTH eq { 211 | row 1 sub col 212 | } { 213 | side //EAST eq { 214 | row col 1 add 215 | } { 216 | (step: bad side ) print side == 217 | } ifelse 218 | } ifelse 219 | } ifelse 220 | } ifelse 221 | } bind def 222 | 223 | /done false def 224 | 225 | /escape {% row col => - 226 | /col exch def 227 | /row exch def 228 | row mexit eq col width 1 sub eq and { 229 | (done)== 230 | row col 231 | /done true store 232 | } { 233 | row col 2 copy mget //CRUMB or mset 234 | row col 235 | [//NORTH //WEST //SOUTH //EAST] {/side exch def 236 | done {exit} if 237 | 2 copy mget /val exch def 238 | val side and 0 ne { 239 | 2 copy side step 2 copy 240 | mget /val exch def 241 | val //CRUMB and 0 eq { 242 | escape 243 | } { 244 | pop pop 245 | } ifelse 246 | } if 247 | } forall 248 | done not { 249 | pop pop 250 | } if 251 | } ifelse 252 | } bind def 253 | 254 | /solve { 255 | % close the entrance 256 | vert 0 get mentrance 1 put 257 | initmaze 258 | % start the escape 259 | /path [mentrance -1 mentrance 0 escape 2 copy 1 add] def 260 | % draw the path 261 | .5 setgray 262 | .5 .5 translate 263 | path 1 get path 0 get moveto 264 | 2 2 path length 1 sub {/i exch def 265 | path i 1 add get path i get lineto 266 | } for 267 | stroke 268 | showpage 269 | } bind def 270 | 271 | % eject the page 272 | 273 | copypage solve 274 | 275 | %%EOF 276 | -------------------------------------------------------------------------------- /operators_dictionary.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The postscript-go Authors. All rights reserved. 2 | // created: 13/12/2010 by Laurent Le Goff 3 | 4 | package ps 5 | 6 | import ( 7 | "log" 8 | ) 9 | 10 | //int dict dict -> Create dictionary with capacity for int elements 11 | func dict(interpreter *Interpreter) { 12 | interpreter.Push(NewDictionary(interpreter.PopInt())) 13 | } 14 | 15 | //dict length int -> Return number of entries in dict 16 | func lengthdict(interpreter *Interpreter) { 17 | dictionary := interpreter.Pop().(Dictionary) 18 | interpreter.Push(float64(len(dictionary))) 19 | } 20 | 21 | //dict maxlength int -> Return current capacity of dict 22 | func maxlength(interpreter *Interpreter) { 23 | interpreter.Pop() 24 | interpreter.Push(float64(999999999)) // push arbitrary value 25 | } 26 | 27 | //dict begin – -> Push dict on dictionary stack 28 | func begin(interpreter *Interpreter) { 29 | interpreter.PushDictionary(interpreter.Pop().(Dictionary)) 30 | } 31 | 32 | //– end – -> Pop current dictionary off dictionary stack 33 | func end(interpreter *Interpreter) { 34 | interpreter.PopDictionary() 35 | } 36 | 37 | //key value def – -> Associate key and value in current dictionary 38 | func def(interpreter *Interpreter) { 39 | value := interpreter.Pop() 40 | name := interpreter.PopName() 41 | if p, ok := value.(*ProcedureDefinition); ok { 42 | value = NewProcedure(p) 43 | } 44 | interpreter.Define(name, value) 45 | } 46 | 47 | //key load value -> Search dictionary stack for key and return associated value 48 | func load(interpreter *Interpreter) { 49 | name := interpreter.PopName() 50 | value, _ := interpreter.FindValueInDictionaries(name) 51 | if value == nil { 52 | log.Printf("Can't find value %s\n", name) 53 | } 54 | interpreter.Push(value) 55 | } 56 | 57 | //key value store – -> Replace topmost definition of key 58 | func store(interpreter *Interpreter) { 59 | value := interpreter.Pop() 60 | key := interpreter.PopName() 61 | _, dictionary := interpreter.FindValueInDictionaries(key) 62 | if dictionary != nil { 63 | dictionary[key] = value 64 | } 65 | } 66 | 67 | //dict key get any -> Return value associated with key in dict 68 | func getdict(interpreter *Interpreter) { 69 | key := interpreter.PopName() 70 | dictionary := interpreter.Pop().(Dictionary) 71 | interpreter.Push(dictionary[key]) 72 | } 73 | 74 | //dict key value put – -> Associate key with value in dict 75 | func putdict(interpreter *Interpreter) { 76 | value := interpreter.Pop() 77 | key := interpreter.PopName() 78 | dictionary := interpreter.Pop().(Dictionary) 79 | dictionary[key] = value 80 | } 81 | 82 | //dict key undef – Remove key and its value from dict 83 | func undef(interpreter *Interpreter) { 84 | key := interpreter.PopName() 85 | dictionary := interpreter.Pop().(Dictionary) 86 | dictionary[key] = nil 87 | } 88 | 89 | //dict key known bool -> Test whether key is in dict 90 | func known(interpreter *Interpreter) { 91 | key := interpreter.PopName() 92 | dictionary := interpreter.Pop().(Dictionary) 93 | interpreter.Push(dictionary[key] != nil) 94 | } 95 | 96 | //key where (dict true) or false -> Find dictionary in which key is defined 97 | func where(interpreter *Interpreter) { 98 | key := interpreter.PopName() 99 | _, dictionary := interpreter.FindValueInDictionaries(key) 100 | if dictionary == nil { 101 | interpreter.Push(false) 102 | } else { 103 | interpreter.Push(dictionary) 104 | interpreter.Push(true) 105 | } 106 | } 107 | 108 | // dict1 dict2 copy dict2 -> Copy contents of dict1 to dict2 109 | func copydict(interpreter *Interpreter) { 110 | dict2 := interpreter.Pop().(Dictionary) 111 | dict1 := interpreter.Pop().(Dictionary) 112 | for key, value := range dict1 { 113 | dict2[key] = value 114 | } 115 | interpreter.Push(dict2) 116 | } 117 | 118 | //dict proc forall – -> Execute proc for each entry in dict 119 | func foralldict(interpreter *Interpreter) { 120 | proc := NewProcedure(interpreter.PopProcedureDefinition()) 121 | dict := interpreter.Pop().(Dictionary) 122 | for key, value := range dict { 123 | interpreter.Push(key) 124 | interpreter.Push(value) 125 | proc.Execute(interpreter) 126 | } 127 | } 128 | 129 | //– currentdict dict -> Return current dictionary 130 | func currentdict(interpreter *Interpreter) { 131 | interpreter.Push(interpreter.PeekDictionary()) 132 | } 133 | 134 | //– systemdict dict -> Return system dictionary 135 | func systemdict(interpreter *Interpreter) { 136 | interpreter.Push(interpreter.SystemDictionary()) 137 | } 138 | 139 | //– userdict dict -> Return writeable dictionary in local VM 140 | func userdict(interpreter *Interpreter) { 141 | interpreter.Push(interpreter.UserDictionary()) 142 | } 143 | 144 | //– globaldict dict -> Return writeable dictionary in global VM 145 | func globaldict(interpreter *Interpreter) { 146 | interpreter.Push(interpreter.UserDictionary()) 147 | } 148 | 149 | //– statusdict dict -> Return product-dependent dictionary 150 | func statusdict(interpreter *Interpreter) { 151 | interpreter.Push(interpreter.UserDictionary()) 152 | } 153 | 154 | //– countdictstack int -> Count elements on dictionary stack 155 | func countdictstack(interpreter *Interpreter) { 156 | interpreter.Push(float64(interpreter.DictionaryStackSize())) 157 | } 158 | 159 | //array dictstack subarray -> Copy dictionary stack into array 160 | func dictstack(interpreter *Interpreter) { 161 | panic("No yet implemenented") 162 | } 163 | 164 | //– cleardictstack – -> Pop all nonpermanent dictionaries off dictionary stack 165 | func cleardictstack(interpreter *Interpreter) { 166 | interpreter.ClearDictionaries() 167 | } 168 | 169 | func initDictionaryOperators(interpreter *Interpreter) { 170 | interpreter.SystemDefine("dict", NewOperator(dict)) 171 | //interpreter.SystemDefine("length", NewOperator(length)) // already define in operators_conflict.go 172 | interpreter.SystemDefine("maxlength", NewOperator(maxlength)) 173 | interpreter.SystemDefine("begin", NewOperator(begin)) 174 | interpreter.SystemDefine("end", NewOperator(end)) 175 | interpreter.SystemDefine("def", NewOperator(def)) 176 | interpreter.SystemDefine("load", NewOperator(load)) 177 | interpreter.SystemDefine("store", NewOperator(store)) 178 | //interpreter.SystemDefine("get", NewOperator(get)) // already define in operators_conflict.go 179 | //interpreter.SystemDefine("put", NewOperator(put)) // already define in operators_conflict.go 180 | interpreter.SystemDefine("undef", NewOperator(undef)) 181 | interpreter.SystemDefine("known", NewOperator(known)) 182 | interpreter.SystemDefine("where", NewOperator(where)) 183 | //interpreter.SystemDefine("copydict", NewOperator(copydict)) // already define in operators_conflict.go 184 | //interpreter.SystemDefine("foralldict", NewOperator(foralldict)) // already define in operators_conflict.go 185 | interpreter.SystemDefine("currentdict", NewOperator(currentdict)) 186 | interpreter.SystemDefine("systemdict", NewOperator(systemdict)) 187 | interpreter.SystemDefine("userdict", NewOperator(userdict)) 188 | interpreter.SystemDefine("globaldict", NewOperator(globaldict)) 189 | interpreter.SystemDefine("statusdict", NewOperator(statusdict)) 190 | interpreter.SystemDefine("countdictstack", NewOperator(countdictstack)) 191 | interpreter.SystemDefine("dictstack", NewOperator(dictstack)) 192 | interpreter.SystemDefine("cleardictstack", NewOperator(cleardictstack)) 193 | } 194 | -------------------------------------------------------------------------------- /interpreter.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The postscript-go Authors. All rights reserved. 2 | // created: 13/12/2010 by Laurent Le Goff 3 | 4 | package ps 5 | 6 | import ( 7 | "io" 8 | "log" 9 | "os" 10 | "strconv" 11 | 12 | "github.com/llgcode/draw2d" 13 | ) 14 | 15 | type Interpreter struct { 16 | valueStack ValueStack 17 | dictionaryStack DictionaryStack 18 | gc draw2d.GraphicContext 19 | } 20 | 21 | type Value interface{} 22 | 23 | type ValueStack []Value 24 | 25 | type Dictionary map[string]Value 26 | 27 | type DictionaryStack []Dictionary 28 | 29 | type Operator interface { 30 | Execute(interpreter *Interpreter) 31 | } 32 | 33 | func NewInterpreter(gc draw2d.GraphicContext) *Interpreter { 34 | interpreter := new(Interpreter) 35 | interpreter.valueStack = make([]Value, 0, 100) 36 | interpreter.dictionaryStack = make([]Dictionary, 2, 10) 37 | interpreter.dictionaryStack[0] = NewDictionary(100) // System dictionary 38 | interpreter.dictionaryStack[1] = NewDictionary(100) // user dictionary 39 | initSystemOperators(interpreter) 40 | interpreter.gc = gc 41 | return interpreter 42 | } 43 | 44 | func NewDictionary(prealloc int) Dictionary { 45 | return make(Dictionary, prealloc) 46 | } 47 | 48 | func (interpreter *Interpreter) SetGraphicContext(gc draw2d.GraphicContext) { 49 | interpreter.gc = gc 50 | } 51 | 52 | func (interpreter *Interpreter) GetGraphicContext() draw2d.GraphicContext { 53 | return interpreter.gc 54 | } 55 | func (interpreter *Interpreter) Execute(reader io.Reader) { 56 | var scanner Scanner 57 | scanner.Init(reader) 58 | token := scanner.Scan() 59 | for token != EOF { 60 | interpreter.scan(&scanner, token) 61 | token = scanner.Scan() 62 | } 63 | } 64 | 65 | func (interpreter *Interpreter) ExecuteFile(filePath string) error { 66 | src, err := os.Open(filePath) 67 | if src == nil { 68 | log.Printf("can't open file; err=%s\n", err.Error()) 69 | return err 70 | } 71 | defer src.Close() 72 | interpreter.Execute(src) 73 | return nil 74 | } 75 | func (interpreter *Interpreter) computeReference(ref string) { 76 | value, _ := interpreter.FindValueInDictionaries(ref) 77 | if value == nil { 78 | log.Printf("Unknown def: %s\n", ref) 79 | } else { 80 | operator, isOperator := value.(Operator) 81 | if isOperator { 82 | operator.Execute(interpreter) 83 | } else { 84 | interpreter.Push(value) 85 | } 86 | } 87 | } 88 | func (interpreter *Interpreter) scan(scanner *Scanner, token int) { 89 | if token == Ident { 90 | switch scanner.TokenText() { 91 | case "true": 92 | interpreter.Push(true) 93 | case "false": 94 | interpreter.Push(false) 95 | case "null": 96 | interpreter.Push(nil) 97 | default: 98 | interpreter.computeReference(scanner.TokenText()) 99 | } 100 | } else if token == '/' { 101 | scanner.Scan() 102 | interpreter.Push("/" + scanner.TokenText()) 103 | } else if token == '[' { 104 | interpreter.Push(interpreter.scanArray(scanner)) 105 | } else if token == '{' { 106 | // procedure 107 | interpreter.Push(interpreter.scanProcedure(scanner)) 108 | } else if token == Float || token == Int { 109 | f, err := strconv.ParseFloat(scanner.TokenText(), 64) 110 | if err != nil { 111 | log.Printf("Float expected: %s\n", scanner.TokenText()) 112 | interpreter.Push(scanner.TokenText()) 113 | } else { 114 | interpreter.Push(f) 115 | } 116 | } else { 117 | interpreter.Push(scanner.TokenText()) 118 | } 119 | } 120 | 121 | func (interpreter *Interpreter) scanArray(scanner *Scanner) []Value { 122 | array := make([]Value, 0, 10) 123 | token := scanner.Scan() 124 | for token != EOF && token != ']' { 125 | if token == Ident { 126 | var v Value = scanner.TokenText() 127 | switch scanner.TokenText() { 128 | case "true": 129 | v = true 130 | case "false": 131 | v = false 132 | case "null": 133 | v = nil 134 | } 135 | array = append(array, v) 136 | } else { 137 | interpreter.scan(scanner, token) 138 | array = append(array, interpreter.Pop()) 139 | } 140 | token = scanner.Scan() 141 | } 142 | return array 143 | } 144 | 145 | func (interpreter *Interpreter) scanProcedure(scanner *Scanner) *ProcedureDefinition { 146 | proceduredef := NewProcedureDefinition() 147 | token := scanner.Scan() 148 | for token != EOF && token != '}' { 149 | if token == Ident { 150 | var v Value = scanner.TokenText() 151 | switch scanner.TokenText() { 152 | case "true": 153 | v = true 154 | case "false": 155 | v = false 156 | case "null": 157 | v = nil 158 | } 159 | proceduredef.Add(v) 160 | } else { 161 | interpreter.scan(scanner, token) 162 | proceduredef.Add(interpreter.Pop()) 163 | } 164 | token = scanner.Scan() 165 | } 166 | return proceduredef 167 | } 168 | 169 | //Dictionary Operation 170 | 171 | func (interpreter *Interpreter) PushDictionary(dictionary Dictionary) { 172 | interpreter.dictionaryStack = append(interpreter.dictionaryStack, dictionary) 173 | } 174 | 175 | func (interpreter *Interpreter) PopDictionary() Dictionary { 176 | stackPointer := len(interpreter.dictionaryStack) - 1 177 | dictionary := interpreter.dictionaryStack[stackPointer] 178 | interpreter.dictionaryStack = interpreter.dictionaryStack[0:stackPointer] 179 | return dictionary 180 | } 181 | 182 | func (interpreter *Interpreter) PeekDictionary() Dictionary { 183 | stackPointer := len(interpreter.dictionaryStack) - 1 184 | return interpreter.dictionaryStack[stackPointer] 185 | } 186 | func (interpreter *Interpreter) ClearDictionaries() { 187 | interpreter.dictionaryStack = interpreter.dictionaryStack[:2] 188 | } 189 | 190 | func (interpreter *Interpreter) DictionaryStackSize() int { 191 | return len(interpreter.dictionaryStack) 192 | } 193 | 194 | func (interpreter *Interpreter) FindValue(name string) Value { 195 | return interpreter.PeekDictionary()[name] 196 | } 197 | 198 | func (interpreter *Interpreter) FindValueInDictionaries(name string) (Value, Dictionary) { 199 | for i := len(interpreter.dictionaryStack) - 1; i >= 0; i-- { 200 | value := interpreter.dictionaryStack[i][name] 201 | if value != nil { 202 | return value, interpreter.dictionaryStack[i] 203 | } 204 | } 205 | return nil, nil 206 | } 207 | 208 | func (interpreter *Interpreter) UserDictionary() Dictionary { 209 | return interpreter.dictionaryStack[0] 210 | } 211 | 212 | func (interpreter *Interpreter) SystemDictionary() Dictionary { 213 | return interpreter.dictionaryStack[0] 214 | } 215 | 216 | func (interpreter *Interpreter) Define(name string, value Value) { 217 | interpreter.PeekDictionary()[name] = value 218 | } 219 | 220 | func (interpreter *Interpreter) SystemDefine(name string, value Value) { 221 | interpreter.dictionaryStack[0][name] = value 222 | } 223 | 224 | //Operand Operation 225 | 226 | func (interpreter *Interpreter) Push(operand Value) { 227 | //log.Printf("Push operand: %v\n", operand) 228 | interpreter.valueStack = append(interpreter.valueStack, operand) 229 | } 230 | 231 | func (interpreter *Interpreter) Pop() Value { 232 | valueStackPointer := len(interpreter.valueStack) - 1 233 | operand := interpreter.valueStack[valueStackPointer] 234 | interpreter.valueStack = interpreter.valueStack[0:valueStackPointer] 235 | //log.Printf("Pop operand: %v\n", operand) 236 | return operand 237 | } 238 | 239 | func (interpreter *Interpreter) PopValues(n int) []Value { 240 | valueStackPointer := len(interpreter.valueStack) - 1 241 | operands := make([]Value, n) 242 | copy(operands, interpreter.valueStack[valueStackPointer-n+1:valueStackPointer+1]) 243 | interpreter.valueStack = interpreter.valueStack[0 : valueStackPointer-n+1] 244 | return operands 245 | } 246 | 247 | func (interpreter *Interpreter) GetValues(n int) []Value { 248 | valueStackPointer := len(interpreter.valueStack) - 1 249 | operands := make([]Value, n) 250 | copy(operands, interpreter.valueStack[valueStackPointer-n+1:valueStackPointer+1]) 251 | return operands 252 | } 253 | 254 | func (interpreter *Interpreter) Get(index int) Value { 255 | valueStackPointer := len(interpreter.valueStack) - 1 256 | return interpreter.valueStack[valueStackPointer-index] 257 | } 258 | 259 | func (interpreter *Interpreter) Peek() Value { 260 | valueStackPointer := len(interpreter.valueStack) - 1 261 | return interpreter.valueStack[valueStackPointer] 262 | } 263 | 264 | func (interpreter *Interpreter) OperandSize() int { 265 | return len(interpreter.valueStack) 266 | } 267 | 268 | func (interpreter *Interpreter) ClearOperands() { 269 | interpreter.valueStack = interpreter.valueStack[0:0] 270 | } 271 | 272 | // misc pop 273 | 274 | func (interpreter *Interpreter) PopFloat() float64 { 275 | operand := interpreter.Pop() 276 | return operand.(float64) 277 | } 278 | 279 | func (interpreter *Interpreter) PopInt() int { 280 | f := interpreter.PopFloat() 281 | return int(f) 282 | } 283 | 284 | func (interpreter *Interpreter) PopOperator() Operator { 285 | operator := interpreter.Pop() 286 | return operator.(Operator) 287 | } 288 | 289 | func (interpreter *Interpreter) PopProcedureDefinition() *ProcedureDefinition { 290 | def := interpreter.Pop() 291 | return def.(*ProcedureDefinition) 292 | } 293 | 294 | func (interpreter *Interpreter) PopName() string { 295 | name := interpreter.Pop().(string) 296 | return name[1:] 297 | } 298 | 299 | func (interpreter *Interpreter) PopString() string { 300 | s := interpreter.Pop().(string) 301 | return s[1 : len(s)-1] 302 | } 303 | 304 | func (interpreter *Interpreter) PopBoolean() bool { 305 | s := interpreter.Pop() 306 | return s.(bool) 307 | } 308 | 309 | func (interpreter *Interpreter) PopArray() []Value { 310 | s := interpreter.Pop() 311 | return s.([]Value) 312 | } 313 | -------------------------------------------------------------------------------- /samples/escher.ps: -------------------------------------------------------------------------------- 1 | %! 2 | % If you're concerned that the cpu in your PostScript printer will atrophy 3 | % from disuse, here is another Escher-like contribution to to keep it busy 4 | % for a while. It uses PostScript color commands, but will still work on 5 | % a monochrome printer (but isn't very pretty in black & white). 6 | % 7 | % The butterflies are arranged in a hexagonal grid (wallpaper group p6), 8 | % and the moveto, lineto, curveto commands used to render the tesselation 9 | % are redefined so as to impose a nonlinear transform that shrinks the 10 | % infinite plane to an ellipse. This is a sleazy way to mimic Escher's 11 | % "circle limit" sorts of things. 12 | % 13 | % The butterfly permimeter was made by imposing all the symmetry constraints 14 | % on a path, and then that path was filled in using Adobe Illustrator 15 | % 16 | % The routines Xform and next_color are easy to change if you want to hack 17 | % with them. The code was written to sacrifice efficiency for readability. 18 | % 19 | % Bob Wallis 20 | % 21 | % UUCP {sun,pyramid,cae780,apple}!weitek!wallis 22 | 23 | %statusdict begin waittimeout 6000 lt % if you have a slow printer, you 24 | % {0 60 6000 setdefaulttimeouts} % might need to uncomment this 25 | %if end 26 | 27 | /nlayers 1 def % 1 takes about 10 minutes on a LW+; 2 takes 4x longer 28 | /warp 1 def % 1 -> ellipsoidal distortion; 0 -> flat Euclidean 29 | /inch {72 mul} def 30 | 31 | /x4 152 def /y4 205.6 def % 6 fold rotation center of bfly 32 | /x12 387.20 def /y12 403.84 def % 3 fold center of bfly 33 | 34 | /dx x4 x12 sub def % [dx,dy] = distance between the 35 | /dy y4 y12 sub def % two fixed points above 36 | 37 | /Dm dx dup mul dy dup mul % magnitude of basis vectors of 38 | add sqrt 3 sqrt mul % parallelogram lattice 39 | def % = |dx,dy| * sqrt(3) 40 | 41 | /Da dy dx atan 30 add def 42 | /D1x Dm Da cos mul def % [D1x, D1y] = basis vector vector #1 43 | /D1y Dm Da sin mul def % = [Dm,0] exp(j30) 44 | 45 | /Da dy dx atan 30 sub def 46 | /D2x Dm Da cos mul def % [D2x, D2y] = basis vector vector #2 47 | /D2y Dm Da sin mul def % = [Dm,0] exp(-j30) 48 | 49 | /m { moveto} def 50 | /L {lineto} def 51 | /S {stroke} def 52 | /c {curveto} def 53 | /f {closepath fill} def 54 | /F {closepath fill} def 55 | /g { setgray} def 56 | 57 | /FillStroke { % fill interior & stroke black border 58 | closepath gsave fill grestore 0 setgray stroke 59 | } def 60 | 61 | % 62 | % Description of 1 butterfly 63 | % 64 | /body { 65 | 314.96 280.19 m 66 | 383.4 261.71 445.11 243.23 513.52 224.68 c 67 | 463.68 256.59 490.26 328.83 446.99 360.76 c 68 | 423.71 347.32 397.08 339.7 367.07 337.9 c 69 | 388.93 358.28 414.14 372.84 442.73 381.58 c 70 | 426.68 398.18 394.07 389.7 387.2 403.84 c 71 | 371.52 404.96 362.56 372.48 340.16 366.88 c 72 | 346.88 396.01 346.88 425.12 340.16 454.24 c 73 | 326.72 427.35 320 400.48 320 373.6 c 74 | 270.71 352.1 221.44 411.23 168.88 384.02 c 75 | 189.04 388.03 202.48 380.4 212.57 366.95 c 76 | 216.72 350.85 209.23 341.46 190.1 338.79 c 77 | 177.34 343.57 167.94 354.17 161.9 370.59 c 78 | 176.06 305.52 132.02 274.05 152 205.6 c 79 | 201.29 257.12 250.56 234.72 299.84 279.52 c 80 | 288.64 266.08 284.16 252.64 286.4 239.2 c 81 | 298.27 223.97 310.15 222.18 322.02 233.82 c 82 | 328.62 249.28 328.51 264.74 314.96 280.19 c 83 | FillStroke 84 | } def 85 | 86 | /eyes { 87 | 294.8125 238.3246 m 88 | 296.9115 238.3246 298.6132 242.7964 298.6132 248.3125 c 89 | 298.6132 253.8286 296.9115 258.3004 294.8125 258.3004 c 90 | 292.7135 258.3004 291.0118 253.8286 291.0118 248.3125 c 91 | 291.0118 242.7964 292.7135 238.3246 294.8125 238.3246 c 92 | closepath gsave 1 g fill grestore 0 g S 93 | 94 | 319.5 241.1782 m 95 | 321.7455 241.1782 323.5659 245.4917 323.5659 250.8125 c 96 | 323.5659 256.1333 321.7455 260.4468 319.5 260.4468 c 97 | 317.2545 260.4468 315.4341 256.1333 315.4341 250.8125 c 98 | 315.4341 245.4917 317.2545 241.1782 319.5 241.1782 c 99 | closepath gsave 1 g fill grestore 0 g S 100 | 0 g 101 | 296.875 242.0939 m 102 | 297.4608 242.0939 297.9356 243.479 297.9356 245.1875 c 103 | 297.9356 246.896 297.4608 248.2811 296.875 248.2811 c 104 | 296.2892 248.2811 295.8143 246.896 295.8143 245.1875 c 105 | 295.8143 243.479 296.2892 242.0939 296.875 242.0939 c 106 | f 107 | 0 g 108 | 318.5 243.7707 m 109 | 319.281 243.7707 319.9142 245.0766 319.9142 246.6875 c 110 | 319.9142 248.2984 319.281 249.6043 318.5 249.6043 c 111 | 317.719 249.6043 317.0858 248.2984 317.0858 246.6875 c 112 | 317.0858 245.0766 317.719 243.7707 318.5 243.7707 c 113 | f 114 | } def 115 | 116 | /stripes { 117 | 292 289 m 118 | 252 294 241 295 213 279 c 119 | 185 263 175 252 159 222 c 120 | S 121 | 285 313 m 122 | 239 326 226 325 206 315 c 123 | 186 305 164 278 161 267 c 124 | S 125 | 298 353 m 126 | 262 342 251 339 237 355 c 127 | 223 371 213 380 201 383 c 128 | S 129 | 330 288 m 130 | 384 293 385 292 418 280 c 131 | 451 268 452 264 473 247 c 132 | S 133 | 342 306 m 134 | 381 311 386 317 410 311 c 135 | 434 305 460 287 474 262 c 136 | S 137 | 345 321 m 138 | 352 357 359 367 379 377 c 139 | 399 387 409 385 426 382 c 140 | S 141 | 327.75 367.75 m 142 | 336.5 392.25 333.682 403.348 335.25 415.5 c 143 | S 144 | 320 364.75 m 145 | 322 361.75 323.5 360.5 326.25 360 c 146 | 329 359.5 332 360.5 334 362.75 c 147 | S 148 | 316.25 356.5 m 149 | 318.75 353.25 320 353 323.25 352.25 c 150 | 326.5 351.5 329 352 331.5 353.25 c 151 | S 152 | 312.5 349 m 153 | 316.75 345.5 318.25 344.5 321.25 343.75 c 154 | 324.25 343 327 344 329.75 346 c 155 | S 156 | 310.75 340.75 m 157 | 314.25 336.5 316.25 335.25 320 335.25 c 158 | 323.75 335.25 327 336.5 329.25 338 c 159 | S 160 | 308.5 332 m 161 | 311.75 328.5 312.5 327.25 317 327 c 162 | 321.5 326.75 325.75 328.25 327.75 329.75 c 163 | S 164 | 305 322 m 165 | 309.5 317.75 310.75 317 315 316.5 c 166 | 319.25 316 322.25 318 324.75 320 c 167 | S 168 | 302.25 311 m 169 | 307 307.5 307.75 306.25 312.75 306 c 170 | 317.75 305.75 320 307.25 323.75 309.5 c 171 | S 172 | 301.25 298.25 m 173 | 304.5 292.75 305.25 292 308.25 292 c 174 | 311.25 292 313.75 293.75 315.75 295.75 c 175 | S 176 | } def 177 | /nostrils { 178 | 0 g 179 | 304.062 227.775 m 180 | 304.599 227.775 305.034 228.883 305.034 230.25 c 181 | 305.034 231.616 304.599 232.724 304.062 232.724 c 182 | 303.525 232.724 303.09 231.616 303.09 230.25 c 183 | 303.09 228.883 303.525 227.775 304.062 227.775 c 184 | f 185 | 304.062 230.25 m 186 | F 187 | 309.562 228.275 m 188 | 310.099 228.275 310.534 229.383 310.534 230.75 c 189 | 310.534 232.116 310.099 233.224 309.562 233.224 c 190 | 309.025 233.224 308.59 232.116 308.59 230.75 c 191 | 308.59 229.383 309.025 228.275 309.562 228.275 c 192 | f 193 | } def 194 | /thorax 195 | { 196 | 327.5 300 m 197 | 316.5 283 315.5 275.5 308 277.5 c 198 | 294 311.5 299 313.5 304 334 c 199 | 309 354.5 315.5 362 322.5 372 c 200 | 329.5 382 327.5 376.5 331 376 c 201 | 334.5 375.5 339.1367 379.1109 339 369 c 202 | 338.5 332 333.4999 324.5 330.5 311.5 c 203 | 0 g S 204 | } def 205 | /spots { 206 | next_color 207 | 192 242.201 m 208 | 202.1535 242.201 210.3848 251.0655 210.3848 262 c 209 | 210.3848 272.9345 202.1535 281.799 192 281.799 c 210 | 181.8465 281.799 173.6152 272.9345 173.6152 262 c 211 | 173.6152 251.0655 181.8465 242.201 192 242.201 c 212 | FillStroke 213 | next_color 214 | 447.5 250.2365 m 215 | 459.6061 250.2365 469.4203 257.5181 469.4203 266.5 c 216 | 469.4203 275.4819 459.6061 282.7635 447.5 282.7635 c 217 | 435.3939 282.7635 425.5797 275.4819 425.5797 266.5 c 218 | 425.5797 257.5181 435.3939 250.2365 447.5 250.2365 c 219 | FillStroke 220 | next_color 221 | 401 369.1005 m 222 | 409.5914 369.1005 416.5563 373.5327 416.5563 379 c 223 | 416.5563 384.4673 409.5914 388.8995 401 388.8995 c 224 | 392.4086 388.8995 385.4436 384.4673 385.4436 379 c 225 | 385.4436 373.5327 392.4086 369.1005 401 369.1005 c 226 | FillStroke 227 | next_color 228 | 249 348.2721 m 229 | 261.4966 348.2721 271.6274 353.9707 271.6274 361 c 230 | 271.6274 368.0293 261.4966 373.7279 249 373.7279 c 231 | 236.5034 373.7279 226.3726 368.0293 226.3726 361 c 232 | 226.3726 353.9707 236.5034 348.2721 249 348.2721 c 233 | FillStroke 234 | } def 235 | 236 | /ncolor 6 def 237 | /cidx 0 def 238 | 239 | /next_color { 240 | cidx ncolor div % hue 241 | .75 % saturation (change these if you like) 242 | .8 % lightness 243 | sethsbcolor 244 | /cidx cidx 1 add ncolor mod def 245 | } def 246 | 247 | /cidx 0 def 248 | 249 | /max_r2 % radius^2 for center of outermost ring of butterflies 250 | Dm nlayers mul 1.05 mul dup mul 251 | def 252 | 253 | /max_radius max_r2 sqrt def 254 | /max_radius_inv 1 max_radius div def 255 | /Dm_inv 1 Dm div def 256 | 257 | % 258 | % Ellipsoidal distortion, maps "nlayers" concentric rings of cells into 259 | % an ellipse centered on page 260 | 261 | % D length of 1 basis vector separating hexagonal cells 262 | % z0 center of 6-fold rotation = origin of shrink xform 263 | % z' = (z - z0)/D new coord system 264 | % |z'| = sqrt(x^2 + [(8.5/11)*y]^2) aspect ratio of paper 265 | % z" = z' * a/M(|z'|) shrink by "a/M(|z|)" as fcn of radius 266 | 267 | % At the max radius, we want the shrunk ellipse to be "W" units wide so it 268 | % just fits our output format - solve for scale factor "a" 269 | 270 | % zmax = n+0.5 for n layers of cells 271 | % zmax * [a/M(zmax)] = W 1/2 width of output on paper 272 | % a = M(zmax)*W/zmax solve for "a" 273 | 274 | %/M{dup mul 1 add sqrt}bind def % M(u) = sqrt(1+|u|^2) = one possible shrink 275 | /M { 1.5 add } bind def % M(u) = (1.5+|u|) = another possible one 276 | /W 3.8 inch def % 1/2 width of ellipse 277 | /zmax 0.5 nlayers add def % radius at last layer of hexagons 278 | /a zmax M W mul zmax div def % a = M(zmax)*W/zmax 279 | 280 | /Xform { % [x0,y0] = ctr ellipse 281 | Matrix transform 282 | /y exch def 283 | /x exch def 284 | /z x dup mul y .773 mul dup mul add sqrt def % ellipse radius 285 | /Scale a z M div def % z=a/M(|z|) 286 | x Scale mul x0 add % magnify back up 287 | y Scale mul y0 add % [x0+x*s, y0+y*s] 288 | } bind def 289 | 290 | 291 | /Helvetica findfont 8 scalefont setfont 292 | 4.25 inch 0.5 inch moveto 293 | (RHW) stringwidth pop -0.5 mul 0 rmoveto 294 | (RHW) show % autograph 295 | 296 | warp 1 eq { % redefine commands to use Xform 297 | /moveto { Xform moveto} bind def 298 | /lineto { Xform lineto} bind def 299 | /curveto { 300 | Xform 6 -2 roll 301 | Xform 6 -2 roll 302 | Xform 6 -2 roll 303 | curveto 304 | } bind def 305 | }if 306 | 307 | 308 | /bfly { % paint 1 butterfly 309 | next_color body 310 | 1 setgray eyes 311 | stripes 312 | 0 setgray nostrils 313 | 0.5 setgray thorax next_color 314 | spots 315 | } def 316 | 317 | /x0 x4 def % center 318 | /y0 y4 def 319 | 320 | /T1matrix % xlate to center of image 321 | x0 neg y0 neg matrix translate 322 | def 323 | 324 | /Smatrix % scale so that 1 basis vector = 1.0 325 | Dm_inv dup matrix scale 326 | def 327 | 328 | /HexCell { % 6 butterflys rotated about center of 329 | /cidx 0 def % 6 fold symmetry 330 | /color 0 def 331 | /T2matrix dx dy matrix translate def 332 | 0 60 300 { 333 | /angle exch def 334 | /Rmatrix angle matrix rotate def 335 | /Matrix % translate, rotate, scale - used by Xform 336 | T1matrix Rmatrix matrix concatmatrix 337 | T2matrix matrix concatmatrix 338 | Smatrix matrix concatmatrix 339 | def 340 | gsave 341 | warp 0 eq % then may use usual PostScript machinery 342 | { % else using Xform 343 | x0 y0 translate angle rotate 344 | .5 dup scale 345 | dx x0 sub dy y0 sub translate 346 | } if 347 | bfly 348 | next_color 349 | grestore 350 | } for 351 | } def 352 | 353 | 354 | %320 x4 sub 240 y4 sub translate 355 | 4.25 inch x4 sub 5.5 inch y4 sub translate 356 | 357 | 358 | 0 setlinewidth 359 | /N 2 def 360 | N neg 1 N { 361 | /i exch def % translate to 362 | N neg 1 N { % i*D1 + j*D2 363 | /j exch def % and draw HexCell 364 | gsave 365 | /dx i D1x mul j D2x mul add def % translate HexCell by 366 | /dy i D1y mul j D2y mul add def % [dx,dy] 367 | /r2 dx dup mul dy dup mul add def % r^2 = |dx,dy|^2 368 | r2 max_r2 lt % inside radius? 369 | { % yes 370 | 1 r2 max_r2 div sub sqrt 2 div 371 | setlinewidth % make skinnier lines 372 | HexCell % 6 butterflies 373 | } 374 | if 375 | grestore 376 | } for 377 | } for 378 | 379 | showpage 380 | 381 | -------------------------------------------------------------------------------- /samples/vasarely.ps: -------------------------------------------------------------------------------- 1 | %! 2 | % vasarely 3 | % Elizabeth D. Zwicky 4 | % zwicky@sgi.com 5 | /vasarelysave save def % prevent residual side effects 6 | % 7 | % Inspired by Vasarely's experiments with tilting circles and squares 8 | % (for instance "Tlinko" and "Betelgeuse" 9 | 10 | %% circles 11 | /part { circle } def /nnrand false def 12 | %% squares 13 | % /part { ngon } def /nn 4 def /nnrand false def 14 | %% random polygons 15 | % /part { ngon } def /nnrand true def 16 | %% random stars (not my favorite on this program) 17 | % /part { nstar } def /nnrand true def 18 | 19 | %% tilt the base shape a random amount? 20 | /twist false def 21 | % /twist true def 22 | 23 | 24 | /rainbow false def 25 | %% To make rainbows 26 | % /rainbow true def 27 | %% Set this to 1 to go through a full range of colors 28 | /rainrange .25 def 29 | 30 | % number of different designs per page 31 | /inheight 2 def 32 | /inwidth 2 def 33 | % number of repeats in a design 34 | /xtimes 10 def 35 | /ytimes 16 def 36 | 37 | %% This sets the relationship between the two hues: comptwo is maximum contrast 38 | /colorway {comptwo} def 39 | %% monochrome comptwo harmtwo harmfour freecolor compthree closeharm 40 | %% origcolor 41 | 42 | %% This sets the brightness and saturation of the colors; vivid makes 43 | %% them both bright 44 | /colorfam {vivid} def 45 | %% vivid jewel intense medium pastel free orig contrast 46 | %% medjewel medvivid vivpastel medpastel 47 | 48 | 49 | %% Only experts below this point! 50 | 51 | 10 srand 52 | /seed rand def 53 | 54 | /starcompensate false def 55 | /constroke 1 def 56 | 57 | 58 | 59 | /circle { 60 | /radius radius 1.33 mul def 61 | currentpoint /herey exch def /herex exch def 62 | herex herey radius 0 360 arc 63 | } def 64 | 65 | /ngon{ % polygon of n sides, n determined by nn 66 | nside 2 div radius rmoveto 67 | nn cvi { 68 | nside neg 0 rlineto 69 | 360 360 nn div sub neg rotate 70 | } repeat 71 | closepath 72 | } def 73 | 74 | /nstar{ % star of n points, n determined by nstarslider 75 | /radius radius 1.33 mul def 76 | currentpoint /herey exch def /herex exch def 77 | 0 radius rmoveto 78 | 90 nstarangle 2 div add neg rotate 79 | nn cvi {nstarside 0 rlineto 80 | 180 180 nstarangle 2 mul sub sub neg rotate 81 | nstarside 0 rlineto 82 | 180 180 360 nn div sub nstarangle 2 mul sub sub rotate 83 | } repeat 84 | 90 nstarangle 2 div add rotate 85 | closepath 86 | } def 87 | 88 | /nstarangle {180 360 nn div sub 3 div} def 89 | /nstarside { 90 | 2 91 | radius 92 | 1 93 | 180 nn div 94 | sin 95 | div 96 | div 97 | mul 98 | nstarangle sin 99 | mul 100 | 180 101 | nstarangle 2 mul 102 | sub 103 | sin 104 | div 105 | } def 106 | 107 | /nside { 108 | 2 109 | radius 110 | 360 nn div 2 div tan 111 | mul 112 | mul 113 | } def 114 | 115 | 116 | /tan { /alpha exch def 117 | alpha sin 118 | 1 alpha sin dup mul sub sqrt 119 | div 120 | } def 121 | 122 | 123 | /pastel { 124 | /backbright high def 125 | /backsat medlow def 126 | /fillbright high def 127 | /fillsat medlow def 128 | /eobright high def 129 | /eosat medlow def 130 | constroke 0 eq { 131 | /strokebright high def 132 | /strokesat medlow def 133 | } 134 | { 135 | /strokebright low def 136 | /strokesat high def 137 | } ifelse 138 | } def 139 | 140 | /jewel { 141 | /fillbright med def 142 | /fillsat high def 143 | /backbright med def 144 | /backsat high def 145 | /eobright med def 146 | /eosat high def 147 | constroke 0 eq { 148 | /strokebright medlow def 149 | /strokesat high def 150 | } 151 | { 152 | /strokebright high def 153 | /strokesat medlow def 154 | } ifelse 155 | } def 156 | 157 | /vivid { 158 | /fillsat 1 def 159 | /fillbright high def 160 | /eosat 1 def 161 | /eobright high def 162 | /backsat 1 def 163 | /backbright high def 164 | constroke 0 eq { 165 | /strokesat 1 def 166 | /strokebright high def 167 | } 168 | { 169 | /strokesat high def 170 | /strokebright medlow def 171 | } ifelse 172 | } def 173 | 174 | /free { 175 | /fillsat anyrand def 176 | /fillbright anyrand def 177 | /eosat anyrand def 178 | /eobright anyrand def 179 | /backsat anyrand def 180 | /backbright anyrand def 181 | /strokesat anyrand def 182 | /strokebright anyrand def 183 | } def 184 | 185 | /contrast { 186 | /sat medhigh def 187 | /bright rand 2 mod 0 eq {medhigh} {medlow} ifelse def 188 | /backsat sat def 189 | /backbright bright def 190 | /eosat sat def 191 | /eobright 1 bright sub def 192 | /fillsat sat def 193 | /fillbright bright def 194 | /strokebright rand 2 mod def 195 | /strokesat rand 2 mod def 196 | 197 | } def 198 | /medium { 199 | /backsat med def 200 | /backbright med def 201 | /eosat med def 202 | /eobright med def 203 | /fillsat med def 204 | /fillbright med def 205 | /strokebright med def 206 | /strokesat med def 207 | 208 | } def 209 | /intense { 210 | /backsat high def 211 | /backbright med def 212 | /eosat high def 213 | /eobright high def 214 | /fillsat high def 215 | /fillbright med def 216 | /strokebright high def 217 | /strokesat high def 218 | 219 | } def 220 | /orig { 221 | /backsat rand 99 mod 55 add 100 div def 222 | /backbright rand 99 mod 35 add 100 div def 223 | /eosat rand 77 mod 22 add 100 div def 224 | /eobright 90 rand 75 mod sub 15 add 100 div def 225 | /fillsat 100 rand 90 mod sub 100 div def 226 | /fillbright 100 rand 45 mod sub 20 add 100 div def 227 | /strokebright 100 rand 55 mod sub 100 div def 228 | /strokesat 100 rand 85 mod sub 100 div def 229 | 230 | } def 231 | 232 | /medjewel { 233 | /alt rand 2 mod def 234 | /backsat alt 0 eq {high} { med} ifelse def 235 | /fillsat alt 0 eq {med} {high} ifelse def 236 | /eosat alt 0 eq {high} {med} ifelse def 237 | /backbright med def 238 | /fillbright med def 239 | /eobright med def 240 | constroke 0 eq { 241 | /strokebright medlow def 242 | /strokesat high def 243 | } 244 | { 245 | /strokebright high def 246 | /strokesat medlow def 247 | } ifelse 248 | } def 249 | 250 | /medvivid { 251 | /alt rand 2 mod def 252 | /backsat alt 0 eq {1} { med} ifelse def 253 | /fillsat alt 0 eq {med} {1} ifelse def 254 | /eosat alt 0 eq {1} {med} ifelse def 255 | /backbright alt 0 eq {high} {med} ifelse def 256 | /eobright alt 0 eq {high} {med} ifelse def 257 | /fillbright alt 0 eq {med} {high} ifelse def 258 | constroke 0 eq { 259 | /strokesat 1 def 260 | /strokebright high def 261 | } 262 | { 263 | /strokesat high def 264 | /strokebright medlow def 265 | } ifelse 266 | } def 267 | /vivpastel { 268 | /backlight rand 2 mod def 269 | /backsat backlight 0 eq {medlow} {1} ifelse def 270 | /eosat backlight 0 eq {medlow} {1} ifelse def 271 | /fillsat backlight 0 eq {1} {medlow} ifelse def 272 | /fillbright high def 273 | /backbright high def 274 | /eobright high def 275 | constroke 0 eq { 276 | /strokesat 1 def 277 | /strokebright high def 278 | } 279 | { 280 | /strokesat high def 281 | /strokebright medlow def 282 | } ifelse 283 | } def 284 | 285 | /medpastel { 286 | /alt rand 2 mod def 287 | /backsat alt 0 eq {medlow} {med} ifelse def 288 | /eosat alt 0 eq {medlow} {med} ifelse def 289 | /fillsat alt 0 eq {med} {medlow} ifelse def 290 | /fillbright alt 0 eq { high } {med} ifelse def 291 | /backbright alt 0 eq {med} { high } ifelse def 292 | /eobright alt 0 eq {med} { high } ifelse def 293 | constroke 0 eq { 294 | /strokebright high def 295 | /strokesat medlow def 296 | } 297 | { 298 | /strokebright low def 299 | /strokesat high def 300 | } ifelse 301 | } def 302 | 303 | /maxcon { 304 | rand 2 mod 1 eq { 305 | /backsat 0 def 306 | /backbright 0 def 307 | /eosat 0 def 308 | /eobright 0 def 309 | /fillsat 0 def 310 | /fillbright 1 def 311 | /strokebright 1 def 312 | /strokesat 0 def 313 | } 314 | { 315 | /backsat 0 def 316 | /backbright 1 def 317 | /eosat 0 def 318 | /eobright 1 def 319 | /fillsat 0 def 320 | /fillbright 0 def 321 | /strokebright 0 def 322 | /strokesat 0 def 323 | } 324 | ifelse 325 | } def 326 | 327 | /monochrome { 328 | /fillhue hue closevary def 329 | /strokehue hue closevary def 330 | /eohue hue closevary def 331 | /backhue hue def 332 | } def 333 | 334 | /blackandwhite { 335 | /fillhue 1 def 336 | /eohue 0 def 337 | /backhue 0 def 338 | /strokehue 1 def 339 | } def 340 | 341 | 342 | /freecolor { 343 | /fillhue anyrand def 344 | /strokehue anyrand def 345 | /eohue anyrand def 346 | /backhue anyrand def 347 | } def 348 | 349 | /purple { 350 | /fillhue rand 15 mod 80 add 100 div def 351 | /backhue rand 15 mod 80 add 100 div def 352 | /strokehue rand 15 mod 80 add 100 div def 353 | /eohue rand 15 mod 80 add 100 div def 354 | /backhue rand 15 mod 80 add 100 div def 355 | } def 356 | 357 | /comptwo { 358 | /fillhue hue closevary def 359 | /strokehue hue .5 add dup 1 gt {1 sub} if def 360 | /backhue strokehue def 361 | /eohue strokehue closevary def 362 | } def 363 | 364 | /compthree { 365 | /backhue hue def 366 | /strokehue hue 1 3 div add dup 1 gt {1 sub} if closevary def 367 | /fillhue strokehue closevary def 368 | /eohue hue 1 3 div sub dup 1 lt { 1 add} if closevary def 369 | } def 370 | 371 | /origcolor { 372 | /backhue hue def 373 | /strokehue 374 | hue 1000 mul cvi 3 mod dup 1 eq 375 | {hue closevary} 376 | {2 eq 377 | {rand 999 mod 1000 div} 378 | {hue .5 add dup 1 gt {1 sub} if } 379 | ifelse 380 | } 381 | ifelse def 382 | /fillhue hue 1000 mul cvi 3 mod dup 1 eq 383 | {hue closevary} 384 | {2 eq 385 | {rand 999 mod 1000 div} 386 | {hue .5 add dup 1 gt {1 sub} if } 387 | ifelse 388 | } 389 | ifelse 390 | def 391 | /eohue hue 1000 mul cvi 2 mod 1 eq 392 | {hue closevary} 393 | {rand 999 mod 1000 div} 394 | ifelse def 395 | } def 396 | 397 | /harmtwo { 398 | /fillhue hue closevary def 399 | /backhue hue def 400 | /strokehue hue .2 add dup 1 gt {1 sub} if closevary def 401 | /eohue strokehue closevary def 402 | } def 403 | 404 | /harmfour { 405 | /fillhue hue closevary def 406 | /backhue hue .1 add dup 1 gt {1 sub} if def 407 | /strokehue hue .2 add dup 1 gt {1 sub} if closevary def 408 | /eohue hue .1 sub dup 1 lt {1 add} if closevary def 409 | } def 410 | 411 | /closeharm { 412 | /fillhue hue def 413 | /backhue hue .05 add dup 1 gt {1 sub} if closevary def 414 | /strokehue hue .1 add dup 1 gt {1 sub} if closevary def 415 | /eohue hue .05 sub dup 0 lt {1 add} if closevary def 416 | } def 417 | 418 | 419 | /high {100 rand 25 mod sub 100 div } def 420 | /med { rand 33 mod 33 add 100 div } def 421 | /medhigh {100 rand 50 mod sub 100 div } def 422 | /medlow {rand 50 mod 100 div } def 423 | /low { rand 25 mod 100 div} def 424 | /anyrand { rand 100 mod 100 div } def 425 | /closevary {rand 70 mod rand 100 mod sub 1000 div add} def 426 | 427 | %rainbow 428 | % {/colorfill {fillhue 1 1 sethsbcolor fill} def} 429 | /colorfill {fillhue fillsat fillbright sethsbcolor fill } def 430 | %ifelse 431 | /colorstroke {strokehue strokesat strokebright sethsbcolor stroke } def 432 | /eocolorfill {eohue eosat eobright sethsbcolor eofill } def 433 | /backfill{ backhue backsat backbright sethsbcolor fill } def 434 | 435 | /xstep { xrange xtimes 1 sub div x 1 sub mul } def 436 | /ystep { yrange ytimes 1 sub div y 1 sub mul} def 437 | 438 | /functionarray [ 439 | {sin abs} 440 | {sin } 441 | {cos } 442 | {cos abs} 443 | {sin dup mul } 444 | {cos dup mul } 445 | {sin abs sqrt } 446 | {cos abs sqrt } 447 | ] def 448 | 449 | /range { /top exch def /bottom exch def /number exch def 450 | % number is between -1 and 1 451 | /rangesize top bottom sub def 452 | number 1 add 2 div 453 | % number is now between 0 and 1 454 | rangesize mul 455 | bottom add 456 | } def 457 | 458 | /drawone { 459 | /radius 460 | width height lt {width 3 div} {height 3 div} ifelse 461 | def 462 | seed srand 463 | 0 0 moveto 464 | /origmatrix [ 0 0 0 0 0 0 ] currentmatrix def 465 | [ % xstep function ystep function2 add 0.4 1.3 range 466 | 1 467 | ystep function xstep function add -0.25 0.25 range 468 | ystep function3 xstep function2 add -0.5 0.5 range 469 | % xstep function4 ystep function mul 0.4 1.3 range 470 | 1 471 | 0 472 | 0 473 | ] 474 | concat 475 | twist {twistdeg rotate} if 476 | part colorfill 477 | origmatrix setmatrix 478 | rainbow 479 | {/fillhue fillhue rainrange xtimes ytimes mul div add dup 1 gt {1 sub} if def} 480 | if 481 | 482 | } def 483 | 484 | /notdrawone { 485 | seed srand 486 | twist {/twistdeg rand 360 mod def} if 487 | nnrand {/nn rand 6 mod 3 add def} if 488 | /x1 rand width 3 div cvi mod width 8 div add def 489 | /y1 rand height 3 div cvi mod height 8 div add def 490 | rand 3 mod dup 1 eq 491 | {pop /x2 rand width 2 div cvi mod def 492 | /y2 rand height 2 div cvi mod def} 493 | { 2 eq 494 | {/x2 y1 def /y2 x1 def} 495 | {/x2 y1 width mul height div def /y2 x1 height mul width div def} 496 | ifelse 497 | } 498 | ifelse 499 | /radius width height gt {width} {height} ifelse 2.5 div def 500 | /stripe rand width 10 div cvi mod 2 add def 501 | starcompensate { /stripe stripe 2 mul def /radius radius 10 nn div mul def } if 502 | /i 1 def 503 | /repeats radius stripe div cvi 1 add def 504 | /nnincr 1 def 505 | repeats { 506 | colorvary {colorfam colorway} if 507 | /i i 1 add def 508 | /radius radius stripe sub def 509 | 510 | } repeat 511 | } def 512 | 513 | 514 | /page { 515 | clippath pathbbox /ury exch def /urx exch def /lly exch def /llx exch 516 | def 517 | /pagewidth urx llx sub 36 72 mul min def 518 | /pageheight ury lly sub 36 72 mul min def 519 | 0 0 moveto 520 | llx lly translate 521 | /outerwidth 522 | pagewidth inwidth div 523 | def 524 | /outerheight 525 | pageheight inheight div 526 | def 527 | /width 528 | outerwidth xtimes div 529 | def 530 | /height 531 | outerheight ytimes div 532 | def 533 | 534 | 535 | 536 | /size 537 | width height gt {width} {height} ifelse 538 | def 539 | inwidth { 540 | inheight { 541 | 542 | /seed rand def 543 | /hue rand 999 mod 1000 div def 544 | colorway colorfam 545 | /x 1 def /y 1 def 546 | nnrand {/nn rand 6 mod 3 add def} if 547 | /twistdeg rand 360 mod def 548 | 549 | /function functionarray rand functionarray length mod get def 550 | /function2 functionarray rand functionarray length mod get def 551 | /function3 functionarray rand functionarray length mod get def 552 | /function4 functionarray rand functionarray length mod get def 553 | 554 | /xrange [ 90 180 270 360 180 360 ] rand 6 mod get def 555 | /yrange [ 90 180 270 360 180 360 ] rand 6 mod get def 556 | initclip 557 | newpath 558 | 0 0 moveto 559 | outerwidth 0 rlineto 560 | 0 outerheight rlineto 561 | outerwidth neg 0 rlineto 562 | backfill 563 | 564 | xtimes { 565 | ytimes{ 566 | /y y 1 add def 567 | width 2 div height 2 div translate 568 | drawone 569 | width 2 div neg height 2 div neg translate 570 | 0 height translate 571 | } repeat 572 | 573 | /y 1 def 574 | /x x 1 add def 575 | width height ytimes mul neg translate 576 | 577 | } repeat 578 | 579 | width xtimes mul neg outerheight translate 580 | } repeat 581 | outerwidth outerheight inheight mul neg translate 582 | } repeat 583 | 584 | } def 585 | 586 | page showpage 587 | clear cleardictstack 588 | vasarelysave restore 589 | -------------------------------------------------------------------------------- /operators_graphics.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The postscript-go Authors. All rights reserved. 2 | // created: 13/12/2010 by Laurent Le Goff 3 | 4 | // Package ps 5 | package ps 6 | 7 | import ( 8 | "image/color" 9 | "log" 10 | "math" 11 | 12 | "github.com/llgcode/draw2d" 13 | ) 14 | 15 | //Path Construction Operators 16 | func newpath(interpreter *Interpreter) { 17 | interpreter.GetGraphicContext().BeginPath() 18 | } 19 | 20 | func closepath(interpreter *Interpreter) { 21 | interpreter.GetGraphicContext().Close() 22 | } 23 | 24 | func currentpoint(interpreter *Interpreter) { 25 | x, y := interpreter.GetGraphicContext().LastPoint() 26 | interpreter.Push(x) 27 | interpreter.Push(y) 28 | } 29 | 30 | func moveto(interpreter *Interpreter) { 31 | y := interpreter.PopFloat() 32 | x := interpreter.PopFloat() 33 | interpreter.GetGraphicContext().MoveTo(x, y) 34 | } 35 | 36 | func rmoveto(interpreter *Interpreter) { 37 | y := interpreter.PopFloat() 38 | x := interpreter.PopFloat() 39 | sx, sy := interpreter.GetGraphicContext().LastPoint() 40 | interpreter.GetGraphicContext().MoveTo(sx+x, sy+y) 41 | } 42 | 43 | func lineto(interpreter *Interpreter) { 44 | y := interpreter.PopFloat() 45 | x := interpreter.PopFloat() 46 | interpreter.GetGraphicContext().LineTo(x, y) 47 | } 48 | 49 | func rlineto(interpreter *Interpreter) { 50 | y := interpreter.PopFloat() 51 | x := interpreter.PopFloat() 52 | sx, sy := interpreter.GetGraphicContext().LastPoint() 53 | interpreter.GetGraphicContext().LineTo(sx+x, sy+y) 54 | } 55 | 56 | func curveto(interpreter *Interpreter) { 57 | cy3 := interpreter.PopFloat() 58 | cx3 := interpreter.PopFloat() 59 | cy2 := interpreter.PopFloat() 60 | cx2 := interpreter.PopFloat() 61 | cy1 := interpreter.PopFloat() 62 | cx1 := interpreter.PopFloat() 63 | interpreter.GetGraphicContext().CubicCurveTo(cx1, cy1, cx2, cy2, cx3, cy3) 64 | } 65 | 66 | func rcurveto(interpreter *Interpreter) { 67 | cy3 := interpreter.PopFloat() 68 | cx3 := interpreter.PopFloat() 69 | cy2 := interpreter.PopFloat() 70 | cx2 := interpreter.PopFloat() 71 | cy1 := interpreter.PopFloat() 72 | cx1 := interpreter.PopFloat() 73 | sx, sy := interpreter.GetGraphicContext().LastPoint() 74 | interpreter.GetGraphicContext().CubicCurveTo(sx+cx1, sy+cy1, sx+cx2, sy+cy2, sx+cx3, sy+cy3) 75 | } 76 | 77 | func arc(interpreter *Interpreter) { 78 | angle2 := interpreter.PopFloat() * (math.Pi / 180.0) 79 | angle1 := interpreter.PopFloat() * (math.Pi / 180.0) 80 | r := interpreter.PopFloat() 81 | y := interpreter.PopFloat() 82 | x := interpreter.PopFloat() 83 | interpreter.GetGraphicContext().ArcTo(x, y, r, r, angle1, angle2-angle1) 84 | } 85 | 86 | func clippath(interpreter *Interpreter) { 87 | //log.Printf("clippath not yet implemented") 88 | } 89 | 90 | func stroke(interpreter *Interpreter) { 91 | interpreter.GetGraphicContext().Stroke() 92 | } 93 | 94 | func fill(interpreter *Interpreter) { 95 | interpreter.GetGraphicContext().Fill() 96 | } 97 | 98 | func gsave(interpreter *Interpreter) { 99 | interpreter.GetGraphicContext().Save() 100 | } 101 | 102 | func grestore(interpreter *Interpreter) { 103 | interpreter.GetGraphicContext().Restore() 104 | } 105 | 106 | func setgray(interpreter *Interpreter) { 107 | gray := interpreter.PopFloat() 108 | color := color.RGBA{uint8(gray * 0xff), uint8(gray * 0xff), uint8(gray * 0xff), 0xff} 109 | interpreter.GetGraphicContext().SetStrokeColor(color) 110 | interpreter.GetGraphicContext().SetFillColor(color) 111 | } 112 | 113 | func setrgbcolor(interpreter *Interpreter) { 114 | blue := interpreter.PopFloat() 115 | green := interpreter.PopFloat() 116 | red := interpreter.PopFloat() 117 | color := color.RGBA{uint8(red * 0xff), uint8(green * 0xff), uint8(blue * 0xff), 0xff} 118 | interpreter.GetGraphicContext().SetStrokeColor(color) 119 | interpreter.GetGraphicContext().SetFillColor(color) 120 | } 121 | 122 | func hsbtorgb(hue, saturation, brightness float64) (red, green, blue int) { 123 | var fr, fg, fb float64 124 | if saturation == 0 { 125 | fr, fg, fb = brightness, brightness, brightness 126 | } else { 127 | H := (hue - math.Floor(hue)) * 6 128 | I := int(math.Floor(H)) 129 | F := H - float64(I) 130 | M := brightness * (1 - saturation) 131 | N := brightness * (1 - saturation*F) 132 | K := brightness * (1 - saturation*(1-F)) 133 | 134 | switch I { 135 | case 0: 136 | fr = brightness 137 | fg = K 138 | fb = M 139 | case 1: 140 | fr = N 141 | fg = brightness 142 | fb = M 143 | case 2: 144 | fr = M 145 | fg = brightness 146 | fb = K 147 | case 3: 148 | fr = M 149 | fg = N 150 | fb = brightness 151 | case 4: 152 | fr = K 153 | fg = M 154 | fb = brightness 155 | case 5: 156 | fr = brightness 157 | fg = M 158 | fb = N 159 | default: 160 | fr, fb, fg = 0, 0, 0 161 | } 162 | } 163 | 164 | red = int(fr*255. + 0.5) 165 | green = int(fg*255. + 0.5) 166 | blue = int(fb*255. + 0.5) 167 | return 168 | } 169 | 170 | func sethsbcolor(interpreter *Interpreter) { 171 | brightness := interpreter.PopFloat() 172 | saturation := interpreter.PopFloat() 173 | hue := interpreter.PopFloat() 174 | red, green, blue := hsbtorgb(hue, saturation, brightness) 175 | color := color.RGBA{uint8(red), uint8(green), uint8(blue), 0xff} 176 | interpreter.GetGraphicContext().SetStrokeColor(color) 177 | interpreter.GetGraphicContext().SetFillColor(color) 178 | } 179 | 180 | func setcmybcolor(interpreter *Interpreter) { 181 | black := interpreter.PopFloat() 182 | yellow := interpreter.PopFloat() 183 | magenta := interpreter.PopFloat() 184 | cyan := interpreter.PopFloat() 185 | 186 | /* cyan = cyan / 255.0; 187 | magenta = magenta / 255.0; 188 | yellow = yellow / 255.0; 189 | black = black / 255.0; */ 190 | 191 | red := cyan*(1.0-black) + black 192 | green := magenta*(1.0-black) + black 193 | blue := yellow*(1.0-black) + black 194 | 195 | red = (1.0-red)*255.0 + 0.5 196 | green = (1.0-green)*255.0 + 0.5 197 | blue = (1.0-blue)*255.0 + 0.5 198 | 199 | color := color.RGBA{uint8(red), uint8(green), uint8(blue), 0xff} 200 | interpreter.GetGraphicContext().SetStrokeColor(color) 201 | interpreter.GetGraphicContext().SetFillColor(color) 202 | } 203 | 204 | func setdash(interpreter *Interpreter) { 205 | interpreter.PopInt() // offset 206 | interpreter.PopArray() // dash 207 | //log.Printf("setdash not yet implemented dash: %v, offset: %d \n", dash, offset) 208 | } 209 | 210 | func setlinejoin(interpreter *Interpreter) { 211 | linejoin := interpreter.PopInt() 212 | switch linejoin { 213 | case 0: 214 | interpreter.GetGraphicContext().SetLineJoin(draw2d.MiterJoin) 215 | case 1: 216 | interpreter.GetGraphicContext().SetLineJoin(draw2d.RoundJoin) 217 | case 2: 218 | interpreter.GetGraphicContext().SetLineJoin(draw2d.BevelJoin) 219 | } 220 | } 221 | 222 | func setlinecap(interpreter *Interpreter) { 223 | linecap := interpreter.PopInt() 224 | switch linecap { 225 | case 0: 226 | interpreter.GetGraphicContext().SetLineCap(draw2d.ButtCap) 227 | case 1: 228 | interpreter.GetGraphicContext().SetLineCap(draw2d.RoundCap) 229 | case 2: 230 | interpreter.GetGraphicContext().SetLineCap(draw2d.SquareCap) 231 | } 232 | } 233 | 234 | func setmiterlimit(interpreter *Interpreter) { 235 | interpreter.PopInt() 236 | //log.Printf("setmiterlimit not yet implemented") 237 | } 238 | 239 | func setlinewidth(interpreter *Interpreter) { 240 | interpreter.GetGraphicContext().SetLineWidth(interpreter.PopFloat()) 241 | } 242 | 243 | func showpage(interpreter *Interpreter) { 244 | //log.Printf("showpage may be an implementation specific, override show page to generate multi page images") 245 | } 246 | 247 | func show(interpreter *Interpreter) { 248 | s := interpreter.PopString() 249 | interpreter.GetGraphicContext().FillString(s) 250 | log.Printf("show not really implemented") 251 | } 252 | 253 | //ax ay string ashow – -> Add (ax , ay) to width of each glyph while showing string 254 | func ashow(interpreter *Interpreter) { 255 | log.Printf("ashow not really implemented") 256 | s := interpreter.PopString() 257 | interpreter.PopFloat() 258 | interpreter.PopFloat() 259 | interpreter.GetGraphicContext().FillString(s) 260 | } 261 | 262 | func findfont(interpreter *Interpreter) { 263 | log.Printf("findfont not yet implemented") 264 | } 265 | 266 | func scalefont(interpreter *Interpreter) { 267 | log.Printf("scalefont not yet implemented") 268 | } 269 | 270 | func setfont(interpreter *Interpreter) { 271 | log.Printf("setfont not yet implemented") 272 | } 273 | 274 | func stringwidth(interpreter *Interpreter) { 275 | interpreter.Push(10.0) 276 | interpreter.Push(10.0) 277 | log.Printf("stringwidth not yet implemented") 278 | } 279 | 280 | func setflat(interpreter *Interpreter) { 281 | interpreter.Pop() 282 | //log.Printf("setflat not yet implemented") 283 | } 284 | 285 | func currentflat(interpreter *Interpreter) { 286 | interpreter.Push(1.0) 287 | //log.Printf("currentflat not yet implemented") 288 | } 289 | 290 | // Coordinate System and Matrix operators 291 | func matrix(interpreter *Interpreter) { 292 | interpreter.Push(draw2d.NewIdentityMatrix()) 293 | } 294 | 295 | func initmatrix(interpreter *Interpreter) { 296 | interpreter.Push(draw2d.NewIdentityMatrix()) 297 | } 298 | 299 | func identmatrix(interpreter *Interpreter) { 300 | tr := interpreter.Pop().(draw2d.Matrix) 301 | ident := draw2d.NewIdentityMatrix() 302 | copy(tr[:], ident[:]) 303 | interpreter.Push(tr) 304 | } 305 | 306 | func defaultmatrix(interpreter *Interpreter) { 307 | tr := interpreter.Pop().(draw2d.Matrix) 308 | ident := draw2d.NewIdentityMatrix() 309 | copy(tr[:], ident[:]) 310 | interpreter.Push(tr) 311 | } 312 | 313 | func currentmatrix(interpreter *Interpreter) { 314 | tr := interpreter.Pop().(draw2d.Matrix) 315 | ctm := interpreter.GetGraphicContext().GetMatrixTransform() 316 | copy(tr[:], ctm[:]) 317 | interpreter.Push(tr) 318 | } 319 | 320 | func setmatrix(interpreter *Interpreter) { 321 | tr := interpreter.Pop().(draw2d.Matrix) 322 | interpreter.GetGraphicContext().SetMatrixTransform(tr) 323 | } 324 | 325 | func concat(interpreter *Interpreter) { 326 | tr := interpreter.Pop().(draw2d.Matrix) 327 | interpreter.GetGraphicContext().ComposeMatrixTransform(tr) 328 | } 329 | func concatmatrix(interpreter *Interpreter) { 330 | tr3 := interpreter.Pop().(draw2d.Matrix) 331 | tr2 := interpreter.Pop().(draw2d.Matrix) 332 | tr1 := interpreter.Pop().(draw2d.Matrix) 333 | result := tr2.Copy() 334 | result.Compose(tr1) 335 | copy(tr3[:], result[:]) 336 | interpreter.Push(tr3) 337 | } 338 | 339 | func transform(interpreter *Interpreter) { 340 | value := interpreter.Pop() 341 | matrix, ok := value.(draw2d.Matrix) 342 | var y float64 343 | if !ok { 344 | matrix = interpreter.GetGraphicContext().GetMatrixTransform() 345 | y = value.(float64) 346 | } else { 347 | y = interpreter.PopFloat() 348 | } 349 | x := interpreter.PopFloat() 350 | 351 | x, y = matrix.TransformPoint(x, y) 352 | interpreter.Push(x) 353 | interpreter.Push(y) 354 | } 355 | 356 | func itransform(interpreter *Interpreter) { 357 | value := interpreter.Pop() 358 | matrix, ok := value.(draw2d.Matrix) 359 | var y float64 360 | if !ok { 361 | matrix = interpreter.GetGraphicContext().GetMatrixTransform() 362 | y = value.(float64) 363 | } else { 364 | y = interpreter.PopFloat() 365 | } 366 | x := interpreter.PopFloat() 367 | x, y = matrix.InverseTransformPoint(x, y) 368 | interpreter.Push(x) 369 | interpreter.Push(y) 370 | } 371 | 372 | func translate(interpreter *Interpreter) { 373 | value := interpreter.Pop() 374 | matrix, ok := value.(draw2d.Matrix) 375 | var y float64 376 | if !ok { 377 | matrix = interpreter.GetGraphicContext().GetMatrixTransform() 378 | y = value.(float64) 379 | } else { 380 | y = interpreter.PopFloat() 381 | } 382 | x := interpreter.PopFloat() 383 | if !ok { 384 | interpreter.GetGraphicContext().Translate(x, y) 385 | } else { 386 | result := matrix.Copy() 387 | result.Translate(x, y) 388 | interpreter.Push(result) 389 | } 390 | } 391 | 392 | func rotate(interpreter *Interpreter) { 393 | value := interpreter.Pop() 394 | matrix, ok := value.(draw2d.Matrix) 395 | var angle float64 396 | if !ok { 397 | matrix = interpreter.GetGraphicContext().GetMatrixTransform() 398 | angle = value.(float64) * math.Pi / 180 399 | } else { 400 | angle = interpreter.PopFloat() * math.Pi / 180 401 | } 402 | if !ok { 403 | interpreter.GetGraphicContext().Rotate(angle) 404 | } else { 405 | result := matrix.Copy() 406 | result.Rotate(angle) 407 | interpreter.Push(result) 408 | } 409 | } 410 | 411 | func scale(interpreter *Interpreter) { 412 | value := interpreter.Pop() 413 | matrix, ok := value.(draw2d.Matrix) 414 | var y float64 415 | if !ok { 416 | matrix = interpreter.GetGraphicContext().GetMatrixTransform() 417 | y = value.(float64) 418 | } else { 419 | y = interpreter.PopFloat() 420 | } 421 | x := interpreter.PopFloat() 422 | if !ok { 423 | interpreter.GetGraphicContext().Scale(x, y) 424 | } else { 425 | result := matrix.Copy() 426 | result.Scale(x, y) 427 | interpreter.Push(result) 428 | } 429 | } 430 | 431 | func initDrawingOperators(interpreter *Interpreter) { 432 | 433 | interpreter.SystemDefine("stroke", NewOperator(stroke)) 434 | interpreter.SystemDefine("fill", NewOperator(fill)) 435 | interpreter.SystemDefine("show", NewOperator(show)) 436 | interpreter.SystemDefine("ashow", NewOperator(ashow)) 437 | interpreter.SystemDefine("showpage", NewOperator(showpage)) 438 | 439 | interpreter.SystemDefine("findfont", NewOperator(findfont)) 440 | interpreter.SystemDefine("scalefont", NewOperator(scalefont)) 441 | interpreter.SystemDefine("setfont", NewOperator(setfont)) 442 | interpreter.SystemDefine("stringwidth", NewOperator(stringwidth)) 443 | 444 | // Graphic state operators 445 | interpreter.SystemDefine("gsave", NewOperator(gsave)) 446 | interpreter.SystemDefine("grestore", NewOperator(grestore)) 447 | interpreter.SystemDefine("setrgbcolor", NewOperator(setrgbcolor)) 448 | interpreter.SystemDefine("sethsbcolor", NewOperator(sethsbcolor)) 449 | interpreter.SystemDefine("setcmybcolor", NewOperator(setcmybcolor)) 450 | interpreter.SystemDefine("setcmykcolor", NewOperator(setcmybcolor)) 451 | interpreter.SystemDefine("setgray", NewOperator(setgray)) 452 | interpreter.SystemDefine("setdash", NewOperator(setdash)) 453 | interpreter.SystemDefine("setlinejoin", NewOperator(setlinejoin)) 454 | interpreter.SystemDefine("setlinecap", NewOperator(setlinecap)) 455 | interpreter.SystemDefine("setmiterlimit", NewOperator(setmiterlimit)) 456 | interpreter.SystemDefine("setlinewidth", NewOperator(setlinewidth)) 457 | // Graphic state operators device dependent 458 | interpreter.SystemDefine("setflat", NewOperator(setflat)) 459 | interpreter.SystemDefine("currentflat", NewOperator(currentflat)) 460 | 461 | // Coordinate System and Matrix operators 462 | interpreter.SystemDefine("matrix", NewOperator(matrix)) 463 | interpreter.SystemDefine("initmatrix", NewOperator(initmatrix)) 464 | interpreter.SystemDefine("identmatrix", NewOperator(identmatrix)) 465 | interpreter.SystemDefine("defaultmatrix", NewOperator(defaultmatrix)) 466 | interpreter.SystemDefine("currentmatrix", NewOperator(currentmatrix)) 467 | interpreter.SystemDefine("setmatrix", NewOperator(setmatrix)) 468 | interpreter.SystemDefine("concat", NewOperator(concat)) 469 | interpreter.SystemDefine("concatmatrix", NewOperator(concatmatrix)) 470 | 471 | interpreter.SystemDefine("transform", NewOperator(transform)) 472 | interpreter.SystemDefine("itransform", NewOperator(itransform)) 473 | interpreter.SystemDefine("translate", NewOperator(translate)) 474 | interpreter.SystemDefine("rotate", NewOperator(rotate)) 475 | interpreter.SystemDefine("scale", NewOperator(scale)) 476 | 477 | //Path Construction Operators 478 | interpreter.SystemDefine("newpath", NewOperator(newpath)) 479 | interpreter.SystemDefine("closepath", NewOperator(closepath)) 480 | interpreter.SystemDefine("currentpoint", NewOperator(currentpoint)) 481 | interpreter.SystemDefine("moveto", NewOperator(moveto)) 482 | interpreter.SystemDefine("rmoveto", NewOperator(rmoveto)) 483 | interpreter.SystemDefine("lineto", NewOperator(lineto)) 484 | interpreter.SystemDefine("rlineto", NewOperator(rlineto)) 485 | interpreter.SystemDefine("curveto", NewOperator(curveto)) 486 | interpreter.SystemDefine("rcurveto", NewOperator(rcurveto)) 487 | interpreter.SystemDefine("arc", NewOperator(arc)) 488 | interpreter.SystemDefine("clippath", NewOperator(clippath)) 489 | } 490 | -------------------------------------------------------------------------------- /scanner.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | // postscript scanner derived form the scanner package of go sources 5 | package ps 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | "io" 11 | "os" 12 | "unicode" 13 | "unicode/utf8" 14 | ) 15 | 16 | // A source position is represented by a Position value. 17 | // A position is valid if Line > 0. 18 | type Position struct { 19 | Filename string // filename, if any 20 | Offset int // byte offset, starting at 0 21 | Line int // line number, starting at 1 22 | Column int // column number, starting at 0 (character count per line) 23 | } 24 | 25 | // IsValid returns true if the position is valid. 26 | func (pos *Position) IsValid() bool { return pos.Line > 0 } 27 | 28 | func (pos Position) String() string { 29 | s := pos.Filename 30 | if pos.IsValid() { 31 | if s != "" { 32 | s += ":" 33 | } 34 | s += fmt.Sprintf("%d:%d", pos.Line, pos.Column) 35 | } 36 | if s == "" { 37 | s = "???" 38 | } 39 | return s 40 | } 41 | 42 | // Predefined mode bits to control recognition of tokens. For instance, 43 | // to configure a Scanner such that it only recognizes (Go) identifiers, 44 | // integers, and skips comments, set the Scanner's Mode field to: 45 | // 46 | // ScanIdents | ScanInts | SkipComments 47 | // 48 | const ( 49 | ScanIdents = 1 << -Ident 50 | ScanInts = 1 << -Int 51 | ScanFloats = 1 << -Float // includes Ints 52 | ScanChars = 1 << -Char 53 | ScanStrings = 1 << -String 54 | ScanRawStrings = 1 << -RawString 55 | ScanComments = 1 << -Comment 56 | SkipComments = 1 << -skipComment // if set with ScanComments, comments become white space 57 | GoTokens = ScanIdents | ScanFloats | ScanChars | ScanStrings | ScanRawStrings | ScanComments | SkipComments 58 | ) 59 | 60 | // The result of Scan is one of the following tokens or a Unicode character. 61 | const ( 62 | EOF = -(iota + 1) 63 | Ident 64 | Int 65 | Float 66 | Char 67 | String 68 | RawString 69 | Comment 70 | skipComment 71 | ) 72 | 73 | var tokenString = map[int]string{ 74 | EOF: "EOF", 75 | Ident: "Ident", 76 | Int: "Int", 77 | Float: "Float", 78 | Char: "Char", 79 | String: "String", 80 | RawString: "RawString", 81 | Comment: "Comment", 82 | } 83 | 84 | // TokenString returns a (visible) string for a token or Unicode character. 85 | func TokenString(tok int) string { 86 | if s, found := tokenString[tok]; found { 87 | return s 88 | } 89 | return fmt.Sprintf("U+%04X", tok) 90 | } 91 | 92 | // GoWhitespace is the default value for the Scanner's Whitespace field. 93 | // Its value selects Go's white space characters. 94 | const GoWhitespace = 1<<'\t' | 1<<'\n' | 1<<'\r' | 1<<' ' 95 | 96 | const bufLen = 1024 // at least utf8.UTFMax 97 | 98 | // A Scanner implements reading of Unicode characters and tokens from an io.Reader. 99 | type Scanner struct { 100 | // Input 101 | src io.Reader 102 | 103 | // Source buffer 104 | srcBuf [bufLen + 1]byte // +1 for sentinel for common case of s.next() 105 | srcPos int // reading position (srcBuf index) 106 | srcEnd int // source end (srcBuf index) 107 | 108 | // Source position 109 | srcBufOffset int // byte offset of srcBuf[0] in source 110 | line int // newline count + 1 111 | column int // character count on line 112 | 113 | // Token text buffer 114 | // Typically, token text is stored completely in srcBuf, but in general 115 | // the token text's head may be buffered in tokBuf while the token text's 116 | // tail is stored in srcBuf. 117 | tokBuf bytes.Buffer // token text head that is not in srcBuf anymore 118 | tokPos int // token text tail position (srcBuf index) 119 | tokEnd int // token text tail end (srcBuf index) 120 | 121 | // One character look-ahead 122 | ch rune // character before current srcPos 123 | 124 | // Error is called for each error encountered. If no Error 125 | // function is set, the error is reported to os.Stderr. 126 | Error func(s *Scanner, msg string) 127 | 128 | // ErrorCount is incremented by one for each error encountered. 129 | ErrorCount int 130 | 131 | // The Mode field controls which tokens are recognized. For instance, 132 | // to recognize Ints, set the ScanInts bit in Mode. The field may be 133 | // changed at any time. 134 | Mode uint 135 | 136 | // The Whitespace field controls which characters are recognized 137 | // as white space. To recognize a character ch <= ' ' as white space, 138 | // set the ch'th bit in Whitespace (the Scanner's behavior is undefined 139 | // for values ch > ' '). The field may be changed at any time. 140 | Whitespace uint64 141 | 142 | // Current token position. The Offset, Line, and Column fields 143 | // are set by Scan(); the Filename field is left untouched by the 144 | // Scanner. 145 | Position 146 | } 147 | 148 | // Init initializes a Scanner with a new source and returns itself. 149 | // Error is set to nil, ErrorCount is set to 0, Mode is set to GoTokens, 150 | // and Whitespace is set to GoWhitespace. 151 | func (s *Scanner) Init(src io.Reader) *Scanner { 152 | s.src = src 153 | 154 | // initialize source buffer 155 | s.srcBuf[0] = utf8.RuneSelf // sentinel 156 | s.srcPos = 0 157 | s.srcEnd = 0 158 | 159 | // initialize source position 160 | s.srcBufOffset = 0 161 | s.line = 1 162 | s.column = 0 163 | 164 | // initialize token text buffer 165 | s.tokPos = -1 166 | 167 | // initialize one character look-ahead 168 | s.ch = s.next() 169 | 170 | // initialize public fields 171 | s.Error = nil 172 | s.ErrorCount = 0 173 | s.Mode = GoTokens 174 | s.Whitespace = GoWhitespace 175 | 176 | return s 177 | } 178 | 179 | // next reads and returns the next Unicode character. It is designed such 180 | // that only a minimal amount of work needs to be done in the common ASCII 181 | // case (one test to check for both ASCII and end-of-buffer, and one test 182 | // to check for newlines). 183 | func (s *Scanner) next() rune { 184 | ch := rune(s.srcBuf[s.srcPos]) 185 | 186 | if ch >= utf8.RuneSelf { 187 | // uncommon case: not ASCII or not enough bytes 188 | for s.srcPos+utf8.UTFMax > s.srcEnd && !utf8.FullRune(s.srcBuf[s.srcPos:s.srcEnd]) { 189 | // not enough bytes: read some more, but first 190 | // save away token text if any 191 | if s.tokPos >= 0 { 192 | s.tokBuf.Write(s.srcBuf[s.tokPos:s.srcPos]) 193 | s.tokPos = 0 194 | } 195 | // move unread bytes to beginning of buffer 196 | copy(s.srcBuf[0:], s.srcBuf[s.srcPos:s.srcEnd]) 197 | s.srcBufOffset += s.srcPos 198 | // read more bytes 199 | i := s.srcEnd - s.srcPos 200 | n, err := s.src.Read(s.srcBuf[i:bufLen]) 201 | s.srcEnd = i + n 202 | s.srcPos = 0 203 | s.srcBuf[s.srcEnd] = utf8.RuneSelf // sentinel 204 | if err != nil { 205 | if s.srcEnd == 0 { 206 | return EOF 207 | } 208 | if err != io.EOF { 209 | s.error(err.Error()) 210 | break 211 | } 212 | } 213 | } 214 | // at least one byte 215 | ch = rune(s.srcBuf[s.srcPos]) 216 | if ch >= utf8.RuneSelf { 217 | // uncommon case: not ASCII 218 | var width int 219 | ch, width = utf8.DecodeRune(s.srcBuf[s.srcPos:s.srcEnd]) 220 | if ch == utf8.RuneError && width == 1 { 221 | s.error("illegal UTF-8 encoding") 222 | } 223 | s.srcPos += width - 1 224 | } 225 | } 226 | 227 | s.srcPos++ 228 | s.column++ 229 | switch ch { 230 | case 0: 231 | // implementation restriction for compatibility with other tools 232 | s.error("illegal character NUL") 233 | case '\n': 234 | s.line++ 235 | s.column = 0 236 | } 237 | 238 | return ch 239 | } 240 | 241 | // Next reads and returns the next Unicode character. 242 | // It returns EOF at the end of the source. It reports 243 | // a read error by calling s.Error, if set, or else 244 | // prints an error message to os.Stderr. Next does not 245 | // update the Scanner's Position field; use Pos() to 246 | // get the current position. 247 | func (s *Scanner) Next() rune { 248 | s.tokPos = -1 // don't collect token text 249 | ch := s.ch 250 | s.ch = s.next() 251 | return ch 252 | } 253 | 254 | // Peek returns the next Unicode character in the source without advancing 255 | // the scanner. It returns EOF if the scanner's position is at the last 256 | // character of the source. 257 | func (s *Scanner) Peek() rune { 258 | return s.ch 259 | } 260 | 261 | func (s *Scanner) error(msg string) { 262 | s.ErrorCount++ 263 | if s.Error != nil { 264 | s.Error(s, msg) 265 | return 266 | } 267 | fmt.Fprintf(os.Stderr, "%s: %s", s.Position, msg) 268 | } 269 | 270 | func (s *Scanner) scanIdentifier() rune { 271 | ch := s.next() // read character after first '_' or letter 272 | for ch == '_' || unicode.IsLetter(ch) || unicode.IsDigit(ch) || ch == '.' || ch == '-' || ch == '`' { 273 | ch = s.next() 274 | } 275 | return ch 276 | } 277 | 278 | func digitVal(ch rune) rune { 279 | switch { 280 | case '0' <= ch && ch <= '9': 281 | return ch - '0' 282 | case 'a' <= ch && ch <= 'f': 283 | return ch - 'a' + 10 284 | case 'A' <= ch && ch <= 'F': 285 | return ch - 'A' + 10 286 | } 287 | return 16 // larger than any legal digit val 288 | } 289 | 290 | func isDecimal(ch rune) bool { return '0' <= ch && ch <= '9' } 291 | 292 | func (s *Scanner) scanMantissa(ch rune) rune { 293 | for isDecimal(ch) { 294 | ch = s.next() 295 | } 296 | return ch 297 | } 298 | 299 | func (s *Scanner) scanFraction(ch rune) rune { 300 | if ch == '.' { 301 | ch = s.scanMantissa(s.next()) 302 | } 303 | return ch 304 | } 305 | 306 | func (s *Scanner) scanExponent(ch rune) rune { 307 | if ch == 'e' || ch == 'E' { 308 | ch = s.next() 309 | if ch == '-' || ch == '+' { 310 | ch = s.next() 311 | } 312 | ch = s.scanMantissa(ch) 313 | } 314 | return ch 315 | } 316 | 317 | func (s *Scanner) scanNumber(ch rune) (int, rune) { 318 | // isDecimal(ch) 319 | if ch == '0' { 320 | // int or float 321 | ch = s.next() 322 | if ch == 'x' || ch == 'X' { 323 | // hexadecimal int 324 | ch = s.next() 325 | for digitVal(ch) < 16 { 326 | ch = s.next() 327 | } 328 | } else { 329 | // octal int or float 330 | seenDecimalDigit := false 331 | for isDecimal(ch) { 332 | if ch > '7' { 333 | seenDecimalDigit = true 334 | } 335 | ch = s.next() 336 | } 337 | if s.Mode&ScanFloats != 0 && (ch == '.' || ch == 'e' || ch == 'E') { 338 | // float 339 | ch = s.scanFraction(ch) 340 | ch = s.scanExponent(ch) 341 | return Float, ch 342 | } 343 | // octal int 344 | if seenDecimalDigit { 345 | s.error("illegal octal number") 346 | } 347 | } 348 | return Int, ch 349 | } 350 | // decimal int or float 351 | ch = s.scanMantissa(ch) 352 | if s.Mode&ScanFloats != 0 && (ch == '.' || ch == 'e' || ch == 'E') { 353 | // float 354 | ch = s.scanFraction(ch) 355 | ch = s.scanExponent(ch) 356 | return Float, ch 357 | } 358 | return Int, ch 359 | } 360 | 361 | func (s *Scanner) scanDigits(ch rune, base, n int) rune { 362 | for n > 0 && int(digitVal(ch)) < base { 363 | ch = s.next() 364 | n-- 365 | } 366 | if n > 0 { 367 | s.error("illegal char escape") 368 | } 369 | return ch 370 | } 371 | 372 | func (s *Scanner) scanEscape(quote rune) rune { 373 | ch := s.next() // read character after '/' 374 | switch ch { 375 | case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote: 376 | // nothing to do 377 | ch = s.next() 378 | case '0', '1', '2', '3', '4', '5', '6', '7': 379 | ch = s.scanDigits(ch, 8, 3) 380 | case 'x': 381 | ch = s.scanDigits(s.next(), 16, 2) 382 | case 'u': 383 | ch = s.scanDigits(s.next(), 16, 4) 384 | case 'U': 385 | ch = s.scanDigits(s.next(), 16, 8) 386 | default: 387 | s.error("illegal char escape") 388 | } 389 | return ch 390 | } 391 | 392 | func (s *Scanner) scanString(quote rune) (n int) { 393 | ch := s.next() // read character after quote 394 | for ch != quote { 395 | if ch == '\n' || ch < 0 { 396 | s.error("literal not terminated") 397 | return 398 | } 399 | if ch == '\\' { 400 | ch = s.scanEscape(quote) 401 | } else { 402 | ch = s.next() 403 | } 404 | n++ 405 | } 406 | return 407 | } 408 | 409 | func (s *Scanner) scanRawString() { 410 | ch := s.next() // read character after '`' 411 | for ch != '`' { 412 | if ch < 0 { 413 | s.error("literal not terminated") 414 | return 415 | } 416 | ch = s.next() 417 | } 418 | } 419 | 420 | func (s *Scanner) scanLineComment() { 421 | ch := s.next() // read character after "//" 422 | for ch != '\n' { 423 | if ch < 0 { 424 | s.error("comment not terminated") 425 | return 426 | } 427 | ch = s.next() 428 | } 429 | } 430 | 431 | func (s *Scanner) scanComment(ch rune) { 432 | s.scanLineComment() 433 | } 434 | 435 | // Scan reads the next token or Unicode character from source and returns it. 436 | // It only recognizes tokens t for which the respective Mode bit (1<<-t) is set. 437 | // It returns EOF at the end of the source. It reports scanner errors (read and 438 | // token errors) by calling s.Error, if set; otherwise it prints an error message 439 | // to os.Stderr. 440 | func (s *Scanner) Scan() int { 441 | ch := s.ch 442 | 443 | // reset token text position 444 | s.tokPos = -1 445 | 446 | redo: 447 | // skip white space 448 | for s.Whitespace&(1< , like "32 /space", 288 | % each of which will define a slot in the encoding and the name to put 289 | % in that slot. Only those names which are needed to over-ride the 290 | % existing ones need be specified. An encoding value (number) may 291 | % be specified followed by more than one name, like "128 /name1 /name2". 292 | % In this case, the names will be sequentially stored in the encoding 293 | % starting at the initial number given (128). 294 | 295 | /R { 296 | findfont begin currentdict dup length dict begin 297 | { %forall 298 | 1 index /FID ne {def} {pop pop} ifelse 299 | } forall 300 | /FontName exch def dup length 0 ne { %if 301 | /Encoding Encoding 256 array copy def 302 | 0 exch { %forall 303 | dup type /nametype eq { %ifelse 304 | Encoding 2 index 2 index put 305 | pop 1 add 306 | }{ %else 307 | exch pop 308 | } ifelse 309 | } forall 310 | } if pop 311 | currentdict dup end end 312 | /FontName get exch definefont pop 313 | } bind def 314 | 315 | % sample use: 316 | % [ 8#360 /apple ] /_Symbol /Symbol R 317 | 318 | % declare page sizes 319 | /D {def} bind def 320 | /B {bind D} bind D 321 | /E {exch D} B 322 | /M {moveto} B 323 | /S {marking {show} 324 | {stringwidth rmoveto 325 | currentpoint pop dup MaxX gt{/MaxX E}{pop}ifelse} 326 | ifelse} B 327 | /H {marking {currentlinewidth exch true charpath 0.5 setlinewidth 328 | gsave 1 setgray fill grestore stroke setlinewidth} 329 | {stringwidth rmoveto 330 | currentpoint pop dup MaxX gt{/MaxX E}{pop}ifelse} 331 | ifelse} B 332 | /Stroke {currentpoint pop dup MaxX gt{/MaxX E}{pop}ifelse marking {stroke}if} B 333 | /W {stringwidth pop} B 334 | /Short 612 D 335 | /Long 792 D 336 | % at this point in the program, the default coordinate system is still in place 337 | /Shrink where {pop 338 | Short 1.0 Shrink sub 0.5 mul mul Long 1.0 Shrink sub 0.5 mul mul translate 339 | Shrink Shrink scale} if 340 | /margin 36 D 341 | /logosize 48 D % memo head size is 56.25 342 | /radius 18 D 343 | /gap 12 D 344 | /offset 8 D 345 | /High 480 D 346 | /Wide 720 D 347 | /CenterX 396 D 348 | /CenterY 336 D 349 | /Top CenterY High 0.5 mul add D 350 | /Tsize 36 D 351 | /Tlead 9 D 352 | /Tspace Tsize Tlead add D 353 | /esize 18 D 354 | /elead 6 D 355 | /espace esize elead add D 356 | /tsize 18 D 357 | /tlead 6 D 358 | /tspace tsize tlead add D 359 | /Ssize 6 D 360 | /Slead 2 D 361 | /Sspace Ssize Slead add D 362 | /setline {1 sub /lineno E} B 363 | /LT {/lineno exch def lineno Lmax gt {/Lmax lineno def}if} B 364 | /eT {/lineno exch def lineno emax gt {/emax lineno def}if} B 365 | /lT {/lineno exch def lineno lmax gt {/lmax lineno def}if} B 366 | /Line {LT lineno 1 sub Tspace mul Base exch sub /Y E} B 367 | /L+ {lineno 1 add LT lineno 1 sub Tspace mul Base exch sub /Y E} B 368 | /L+2 {lineno 2 add LT lineno 1 sub Tspace mul Base exch sub /Y E} B 369 | /eline {eT lineno 1 sub espace mul ebase exch sub /Y E} B 370 | /e+ {lineno 1 add eT lineno 1 sub espace mul ebase exch sub /Y E} B 371 | /e+2 {lineno 2 add eT lineno 1 sub espace mul ebase exch sub /Y E} B 372 | /line {lT lineno 1 sub tspace mul base exch sub /Y E} B 373 | /l+ {lineno 1 add lT lineno 1 sub tspace mul base exch sub /Y E} B 374 | /l+2 {lineno 2 add lT lineno 1 sub tspace mul base exch sub /Y E} B 375 | /C1 {col1 Y moveto} B 376 | /C2 {col2 Y moveto} B 377 | /C3 {col3 Y moveto} B 378 | /C4 {col4 Y moveto} B 379 | /C5 {col5 Y moveto} B 380 | /C6 {col6 Y moveto} B 381 | /C7 {col7 Y moveto} B 382 | /C8 {col8 Y moveto} B 383 | /C9 {col9 Y moveto} B 384 | /RC [ 8#375 /copyright /registered /trademark ] def 385 | RC /_Times-Roman /Times-Roman R 386 | /foliofont /_Times-Roman findfont logosize offset 3 mul sub scalefont D 387 | /FO {foliofont setfont} B 388 | /textsize /_Times-Roman findfont tsize scalefont D 389 | /TX {textsize setfont} B 390 | /TXS {currentfont exch TX S setfont} B 391 | RC /_Times-Italic /Times-Italic R 392 | /italics /_Times-Italic findfont tsize scalefont D 393 | /TI {italics setfont} B 394 | /TIS {currentfont exch TI S setfont} B 395 | RC /_Times-BoldItalic /Times-BoldItalic R 396 | /bold_italics /_Times-BoldItalic findfont tsize scalefont D 397 | /TJ {bold_italics setfont} B 398 | /TJS {currentfont exch TJ S setfont} B 399 | RC /_Times-Bold /Times-Bold R 400 | /boldfont /_Times-Bold findfont tsize scalefont D 401 | /TB {boldfont setfont} B 402 | /TBS {currentfont exch TB S setfont} B 403 | /monospace /Courier-Bold findfont tsize scalefont D 404 | /CM {monospace setfont} B 405 | /CMS {currentfont exch CM S setfont} B 406 | /monolite /Courier findfont tsize scalefont D 407 | /CR {monolite setfont} B 408 | /CRS {currentfont exch CR S setfont} B 409 | /monoitalic /Courier-Oblique findfont tsize scalefont D 410 | /CI {monoitalic setfont} B 411 | /CIS {currentfont exch CI S setfont} B 412 | /monoBI /Courier-BoldOblique findfont tsize scalefont D 413 | /CJ {monoBI setfont} B 414 | /CJS {currentfont exch CJ S setfont} B 415 | /narrowmono /Courier-Bold findfont [.8 tsize mul 0 0 tsize 0 0] makefont D 416 | /SC {narrowmono setfont} B 417 | /SCS {currentfont exch SC S setfont} B 418 | /largesize /_Times-Roman findfont Tsize scalefont D 419 | /LG {largesize setfont} B 420 | /LGS {currentfont exch LG S setfont} B 421 | /smallfont /_Times-Roman findfont Ssize scalefont D 422 | /SM {smallfont setfont} B 423 | /SMS {currentfont exch SM S setfont} B 424 | /symbolfont /Symbol findfont tsize scalefont D 425 | /SY {symbolfont setfont} B 426 | /microsymbol /Symbol findfont tsize 0.4 mul scalefont D 427 | /MY {microsymbol setfont} B 428 | /pointerfont /ZapfDingbats findfont tsize scalefont D 429 | /PT {pointerfont setfont} B 430 | /FNALfont /Logo findfont tsize scalefont D 431 | /FN {FNALfont setfont} B 432 | /Item {currentfont SY(\267)S setfont} B 433 | /Note {currentfont PT(-)S setfont} B 434 | /Here {currentfont PT(+)S setfont} B 435 | /Gives {currentfont SY(\336)S setfont} B 436 | /Moon {currentfont PT(m)S setfont} B 437 | /FNAL {currentfont FN(F)S setfont} B 438 | /Block1 {currentfont PT(y)S setfont} B 439 | /Block2 {currentfont PT(z)S setfont} B 440 | /Start {currentpoint gsave currentpoint translate MY (\355) stringwidth 441 | pop -.5 mul tsize -.5 mul moveto (\255) S grestore moveto } B 442 | /Mark {currentpoint gsave currentpoint translate MY (\355) stringwidth 443 | pop -.5 mul tsize -.5 mul moveto (\335) S grestore moveto } B 444 | /More {660 108 M currentfont TX ((more)) show setfont} B 445 | /center {/Text E Long Text stringwidth pop sub 0.5 mul exch moveto 446 | Text marking{show}{pop}ifelse} B 447 | /Center {Long exch sub 0.5 mul exch moveto} B 448 | /Fickle {Index lineno eq {Here} {Item} ifelse} B 449 | /RVS {marking {dup save exch currentpoint newpath moveto 450 | 1 0 rmoveto true charpath pathbbox 451 | 1 add /Uy E 1 add /Ux E 1 sub /Ly E 1 sub /Lx E newpath 452 | Lx Ux add 0.5 mul Ly moveto 453 | Lx Ly Lx Uy 1 arcto pop pop pop pop 454 | Lx Uy Ux Uy 1 arcto pop pop pop pop 455 | Ux Uy Ux Ly 1 arcto pop pop pop pop 456 | Ux Ly Lx Ly 1 arcto pop pop pop pop 457 | closepath 458 | 0 setgray fill restore 459 | currentgray exch 1 setgray 1 0 rmoveto show 1 0 rmoveto setgray} 460 | {stringwidth rmoveto 2 0 rmoveto 461 | currentpoint pop dup MaxX gt{/MaxX E}{pop}ifelse} 462 | ifelse} B 463 | /Frame { 464 | /ll E /el E /Ll E 465 | /Lmax 0 D /emax 0 D /lmax 0 D 466 | /Gaps 1 Ll 1 lt{0 /THght 0 D}{1 /THght Ll Tspace mul Tlead sub D}ifelse add 467 | el 1 lt{0 /eHght 0 D}{1 /eHght el espace mul elead sub D}ifelse add 468 | ll 1 lt{0 /tHght 0 D}{1 /tHght ll tspace mul tlead sub D}ifelse add D 469 | /GapSize High THght sub eHght sub tHght sub Gaps div D 470 | /Base Top Ll 1 ge{GapSize sub Tsize sub}if D 471 | /ebase Top Ll 1 ge{GapSize sub THght sub}if 472 | el 1 ge{GapSize sub esize sub}if D 473 | /base Top Ll 1 ge{GapSize sub THght sub}if 474 | el 1 ge{GapSize sub eHght sub}if 475 | ll 1 ge{GapSize sub tsize sub}if D 476 | 477 | /Rnd {rand 2147483647.0 div mul add} bind def 478 | 479 | % size of rounded box allowing for logo at top 480 | /boxx Long margin dup add sub D 481 | /boxy Short margin dup add sub logosize sub gap sub D 482 | % left edge of logo area 483 | /logox Long margin sub logosize 1.2 mul sub 484 | /Helvetica-Bold findfont logosize 0.5 mul scalefont setfont (Fermilab) 485 | stringwidth pop sub D 486 | 487 | % left edge of titling area 488 | /titlesize logosize 6 div D 489 | /titlefont /Helvetica-Bold findfont titlesize 1.6 mul scalefont D 490 | /giverfont /Times-Roman findfont titlesize 0.8 mul scalefont D 491 | /titlex logox gap sub 492 | titlefont setfont talktitle stringwidth pop 493 | giverfont setfont talkgiver stringwidth pop 2 copy lt {exch} if pop 494 | talkdept stringwidth pop 2 copy lt {exch} if pop 495 | talkaddr stringwidth pop 2 copy lt {exch} if pop 496 | talkcopyr stringwidth pop 2 copy lt {exch} if pop 497 | sub D 498 | 499 | % determine folio box size 500 | /folioboxx foliofont setfont folio stringwidth pop offset dup add add D 501 | /folioboxy logosize offset sub D 502 | 503 | % determine folio box x origin 504 | /folioorgx titlex margin add gap sub offset sub folioboxx sub 2 div D 505 | 506 | % rotate to landscape orientation 507 | 90 rotate 508 | 509 | % move origin to lower left hand corner of sheet 510 | 0 Short neg translate 511 | 512 | % draw logo in lower right hand corner 513 | save 514 | /DoColor where {pop DoColor {.4 .6 Rnd .2 .8 Rnd .2 .8 Rnd setrgbcolor}if}if 515 | logox margin translate 516 | /Logo findfont logosize scalefont setfont 0 0 moveto (F) show 517 | /DoColor where {pop DoColor {0 setgray}if}if 518 | /Helvetica-Bold findfont 519 | logosize 0.5 mul scalefont setfont 520 | logosize 1.2 mul logosize 0.375 mul moveto 521 | (Fermilab) show 522 | restore 523 | 524 | % add talk data 525 | save 526 | titlex margin translate 527 | 0 titlesize 4 mul moveto titlefont setfont talktitle show 528 | 0 titlesize 3 mul moveto giverfont setfont talkgiver show 529 | 0 titlesize 2 mul moveto talkdept show 530 | 0 titlesize moveto talkaddr show 531 | 0 0 moveto talkcopyr show 532 | restore 533 | 534 | % add folio 535 | save 536 | 0 setlinecap % square butt ends 537 | 1 setlinejoin % rounded corners 538 | 0.5 setlinewidth % width of line to draw 539 | /box {1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath} B 540 | folioorgx margin translate 541 | gsave 542 | offset 0 translate 0 0 moveto 0 setgray folioboxx folioboxy box fill 543 | grestore 544 | gsave 545 | 0 offset translate 546 | 0 0 moveto 0.95 setgray folioboxx folioboxy box fill 547 | 0 0 moveto 0 setgray folioboxx folioboxy box stroke 548 | grestore 549 | gsave 550 | offset dup dup add translate 0 0 moveto foliofont setfont 551 | folio true charpath 552 | gsave 1 setgray fill grestore stroke 553 | 554 | grestore 555 | restore 556 | 557 | % 558 | % draw rounded box 559 | % 560 | save 561 | /DoColor where {pop DoColor {0 0 1 setrgbcolor}if}if 562 | % start a new path 563 | % line characters 564 | 0 setlinecap % square butt ends 565 | 1 setlinejoin % rounded corners 566 | 3 setlinewidth % width of line to draw 567 | newpath 568 | % make lower left corner of the rounded box the origin 569 | margin margin logosize add gap add translate 570 | % center of bottom edge 571 | boxx 0.5 mul 0 moveto 572 | % draw lower left corner to center of left edge 573 | 0 0 0 boxy mul 0.5 radius arcto pop pop pop pop 574 | % draw upper left corner to center of top edge 575 | 0 boxy boxx 0.5 mul boxy radius arcto pop pop pop pop 576 | % draw upper right corner to center of right edge 577 | boxx boxy boxx boxy 0.5 mul radius arcto pop pop pop pop 578 | % draw lower left corner to near center of bottom edge 579 | boxx 0 boxx mul 0.5 6 add 0 radius arcto pop pop pop pop 580 | % close the path 581 | closepath 582 | % draw the box 583 | stroke 584 | restore 585 | 586 | save 587 | filenames {756 SM filename stringwidth pop sub 588 moveto filename show}if 588 | restore} B 589 | 590 | /Check { 591 | filenames { 592 | Lmax dup add emax add lmax add 18 lt 593 | {Lmax Ll ne emax el ne or lmax ll ne or} 594 | {Lmax Ll ne emax el ne or lmax 1 add ll ne or} ifelse 595 | { 36 588 moveto SM 596 | Lmax =string cvs show (/)show Ll =string cvs show ( )show 597 | emax =string cvs show (/)show el =string cvs show ( )show 598 | lmax =string cvs show (/)show ll =string cvs show 599 | } if 600 | } if } B 601 | 602 | % 603 | % draw rounded box 604 | % 605 | /drbradius tsize 3 div D 606 | /drb { /drbtext E /drbxy E /drbxx E 607 | marking 608 | { save 609 | currentpoint translate 610 | 0 setlinecap % square butt ends 611 | 1 setlinejoin % rounded corners 612 | 0.5 setlinewidth % width of line to draw 613 | newpath 614 | % the origin is the lower left corner of the rounded box 615 | % start drawing the box at the center of the bottom edge 616 | drbxx 0.5 mul 0 moveto 617 | % draw lower left corner to center of left edge 618 | 0 0 0 drbxy mul 0.5 drbradius arcto pop pop pop pop 619 | % draw upper left corner to center of top edge 620 | 0 drbxy drbxx 0.5 mul drbxy drbradius arcto pop pop pop pop 621 | % draw upper right corner to center of right edge 622 | drbxx drbxy drbxx drbxy 0.5 mul drbradius arcto pop pop pop pop 623 | % draw lower left corner to near center of bottom edge 624 | drbxx 0 drbxx mul 0.5 6 add 0 drbradius arcto pop pop pop pop 625 | % close the path 626 | closepath 627 | % draw the box 628 | stroke 629 | % place the text 630 | drbxx drbtext stringwidth pop sub 0.5 mul 631 | drbxy tspace sub 0.5 mul tlead add 632 | moveto drbtext show 633 | restore 634 | }{ 635 | /drbright currentpoint pop drbxx add 0.25 add D 636 | drbright MaxX gt {/MaxX drbright D} if 637 | } ifelse 638 | } B 639 | 640 | /PlaceText { 641 | /Markings E 642 | save /marking false D /MaxX 0 D Markings 643 | CenterX MaxX 0.5 mul sub 0 translate 644 | /marking true D Markings lmax exch restore /lmax exch def} B 645 | 646 | /MeasureText {/Markings E /marking false D /MaxX 0 D /Base Top D /base Top D 647 | Markings /OffsetX CenterX MaxX 0.5 mul sub D} B 648 | 649 | /MarkText {save OffsetX 0 translate /marking true D Markings restore} B 650 | 651 | /marking true D 652 | /filenames false D 653 | /OffsetX 90 D 654 | /col1 0 D 655 | /col2 30 D 656 | /col3 60 D 657 | /col4 90 D 658 | /col5 120 D 659 | /col6 150 D 660 | /col7 180 D 661 | /col8 210 D 662 | /col9 240 D 663 | 664 | %% 665 | %% Used to divide the page into two sections divided horizonally 666 | %% 667 | 668 | /Scale 0.625 D 669 | /SubPageX Short Scale mul D 670 | /SubPageY Long Scale mul D 671 | /AdjustX -6 D 672 | /AdjustUX Long -0.5 mul AdjustX sub SubPageX sub D 673 | /AdjustLX Long -0.5 mul AdjustX add D 674 | /AdjustY Short SubPageY sub 0.5 mul D 675 | 676 | /Upper{Handout 677 | {-90 rotate AdjustUX AdjustY translate Scale Scale scale }if}B 678 | /Lower{Handout 679 | {-90 rotate AdjustLX AdjustY translate Scale Scale scale }if}B 680 | 681 | %% 682 | %% Used to print handout format text 683 | %% 684 | /LineBuffer 128 string D 685 | /in{72 mul}B /mm{2.8346 mul}B /pt{}B /by{}B 686 | /PageSize{/long E /short E}B 687 | /land{90 rotate 0 short neg translate /High short D /Wide long D}B 688 | /port{/High long D /Wide short D}B 689 | /Offset{/Yoff E /Xoff E Xoff Yoff translate 690 | /High High Yoff sub Yoff sub D /Wide Wide Xoff sub Xoff sub D}B 691 | /LineSize{/Lhigh E /Lwide E 692 | /Lvert High Lhigh div cvi D /Lhori Wide Lwide div cvi D}B 693 | /SetFont{findfont exch /FS E [ .8 FS mul 0 0 FS 0 0 ] makefont setfont}B 694 | /R3{3 1 roll}B 695 | /DC{2 index Lhori 1 sub ge 696 | {NewPage pop pop 0 Lvert false} 697 | {R3 pop Lvert R3 1 add R3}ifelse}B 698 | /DR{1 index 0 le{DC}if exch 1 sub exch}B 699 | /T{exch pop true exch 3 index Lwide mul 3 index Lhigh mul M show}B 700 | /ReadLine {currentfile LineBuffer readline exch /Text E not Text EOF eq or}B 701 | % 702 | % Sheet description 703 | % 704 | /NoteText{/EOF E Handout 705 | {8.5 in by 11 in PageSize land 36 36 Offset 706 | 360 pt by 12 pt LineSize 11 /Courier-Bold SetFont 707 | save 0 Lvert false 708 | {ReadLine {exit}{DR Text length 0 ne {Text T}if}ifelse}loop 709 | pop pop pop restore} 710 | {{ReadLine {exit}if}loop} 711 | ifelse restore}B 712 | 713 | /Viewgraph {save Upper} B 714 | /EndViewgraph {Check restore} B 715 | /Notes {save Lower (EndNotes) NoteText} B 716 | 717 | end def 718 | 719 | /PageTop {PageFrame begin save 100 dict begin} bind def 720 | /PageBottom {end restore end} bind def 721 | /DoColor where {pop}{/DoColor false def}ifelse 722 | /Handout where {pop}{/Handout false def}ifelse 723 | % titling data 724 | /talktitle (Just a little PostScript) def 725 | /talkgiver (Randolph J. Herber, herber@fnal.fnal.gov, 1 630 840 2966 CDF PK149O) 726 | def 727 | /talkdept (Computing Division/Operating System Support/CDF Task Force) def 728 | /talkaddr (P.O. Box 500, Mail Stop 234 (WH6W), Batavia, IL 60510) def 729 | /talkcopyr () def 730 | 731 | /filenames true def 732 | %%EndProlog 733 | %%Page: Examples12 1 734 | PageTop 735 | Viewgraph 736 | /folio (Examples) def 737 | /filename (examples.12) def 738 | 739 | 740 | /@ {transform .5 add floor exch .5 add floor exch itransform} bind def 741 | /! {dtransform .5 add floor exch .5 add floor exch idtransform} bind def 742 | 1 0 19 Frame 743 | 744 | LG 1 Line Y (Many different ways to draw two parallel lines) center 745 | 746 | 8 line save /showpage {} def 146 Y @ translate .2 dup scale 747 | gsave newpath 0 0 moveto 612 0 rlineto 0 792 rlineto -612 0 rlineto closepath 748 | DoColor{0 0 1 setrgbcolor}if stroke grestore 749 | 66 146 @ translate 750 | 2 setlinewidth 751 | 0 0 @ moveto 500 0 ! rlineto stroke 752 | 0 500 @ moveto 500 0 ! rlineto stroke 753 | showpage 754 | restore 755 | 756 | 8 line save /showpage {} def 271 Y @ @ translate .2 dup scale 757 | gsave newpath 0 0 moveto 612 0 rlineto 0 792 rlineto -612 0 rlineto closepath 758 | DoColor{0 0 1 setrgbcolor}if stroke grestore 759 | 66 146 @ translate 760 | 2 setlinewidth 761 | 0 0 @ moveto 762 | gsave 763 | 0 500 @ moveto 500 0 ! rlineto stroke 764 | grestore 765 | 500 0 ! rlineto stroke 766 | showpage 767 | restore 768 | 769 | 8 line save /showpage {} def 396 Y @ translate .2 dup scale 770 | gsave newpath 0 0 moveto 612 0 rlineto 0 792 rlineto -612 0 rlineto closepath 771 | DoColor{0 0 1 setrgbcolor}if stroke grestore 772 | 66 146 @ translate 773 | 2 setlinewidth 774 | [500] 0 setdash 775 | 0 0 @ moveto 500 0 ! rlineto 0 500 ! rlineto -500 0 ! rlineto closepath stroke 776 | showpage 777 | restore 778 | 779 | 8 line save /showpage {} def 521 Y @ translate .2 dup scale 780 | gsave newpath 0 0 moveto 612 0 rlineto 0 792 rlineto -612 0 rlineto closepath 781 | DoColor{0 0 1 setrgbcolor}if stroke grestore 782 | 66 146 @ translate 783 | 2 setlinewidth 784 | [50] 0 setdash 785 | 0 0 @ moveto 500 0 ! rlineto stroke 786 | 500 500 @ moveto -500 0 ! rlineto stroke 787 | 500 0 @ moveto -500 0 ! rlineto stroke 788 | 0 500 @ moveto 500 0 ! rlineto stroke 789 | showpage 790 | restore 791 | 792 | 16 line save /showpage {} def 146 Y @ translate .2 dup scale 793 | gsave newpath 0 0 moveto 612 0 rlineto 0 792 rlineto -612 0 rlineto closepath 794 | DoColor{0 0 1 setrgbcolor}if stroke grestore 795 | 66 146 @ translate 796 | 2 setlinewidth 797 | [50] 0 setdash 798 | .2 setgray 0 0 @ moveto 500 0 ! rlineto stroke 799 | .4 setgray 500 500 @ moveto -500 0 ! rlineto stroke 800 | .6 setgray 500 0 @ moveto -500 0 ! rlineto stroke 801 | .8 setgray 0 500 @ moveto 500 0 ! rlineto stroke 802 | showpage 803 | restore 804 | 805 | 16 line save /showpage {} def 271 Y @ translate .2 dup scale 806 | gsave newpath 0 0 @ moveto 612 0 rlineto 0 792 rlineto -612 0 rlineto closepath 807 | DoColor{0 0 1 setrgbcolor}if stroke grestore 808 | 66 146 @ translate 809 | /B {bind def} dup exec 810 | /E {exch def} B 811 | /Box {/W E /H E 812 | @ moveto W 0 ! rlineto 0 H ! rlineto W neg 0 ! rlineto closepath} B 813 | 0 -1 2 500 Box 0 499 2 500 Box fill 814 | showpage 815 | restore 816 | 817 | 16 line save /showpage {} def 390 Y @ translate .2 dup scale 818 | gsave newpath 0 0 @ moveto 612 0 rlineto 0 792 rlineto -612 0 rlineto closepath 819 | DoColor{0 0 1 setrgbcolor}if stroke grestore 820 | 66 146 @ translate 821 | /B {bind def} dup exec 822 | /E {exch def} B 823 | /Box {/W E /H E 824 | @ moveto W 0 ! rlineto 0 H ! rlineto W neg 0 ! rlineto closepath} B 825 | 0 -2 504 500 Box fill 1 setgray 0 1 498 500 Box fill 826 | showpage 827 | restore 828 | 829 | 16 line save /showpage {} def 521 Y @ translate .2 dup scale 830 | gsave newpath 0 0 @ moveto 612 0 rlineto 0 792 rlineto -612 0 rlineto closepath 831 | DoColor{0 0 1 setrgbcolor}if stroke grestore 832 | 66 146 @ translate 833 | 2 setlinewidth 834 | [5] 0 setdash 835 | newpath 836 | 500 0 0 0 -500 0 500 500 -500 0 500 0 500 0 0 500 837 | 4 {@ moveto ! rlineto} bind repeat 838 | stroke 839 | showpage 840 | restore 841 | 842 | { 843 | 18 setline TX 844 | l+ C1(These look alike and have vastly different PostScript language codes.)S 845 | } PlaceText 846 | EndViewgraph 847 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 848 | %% Notes lines should not be longer than 65 characters. %% 849 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 850 | Notes 851 | ==> Q1.ps <== 852 | %!PS-Adobe-3.0 EPSF-3.0 853 | %%BoundingBox: 55 145 557 647 854 | %%Pages: 1 855 | %%EndComments 856 | 66 146 translate 2 setlinewidth 857 | 0 0 moveto 500 0 rlineto stroke 858 | 0 500 moveto 500 0 rlineto stroke 859 | showpage 860 | 861 | ==> Q2.ps <== 862 | %!PS-Adobe-3.0 EPSF-3.0 863 | %%BoundingBox: 55 145 557 647 864 | %%Pages: 1 865 | %%EndComments 866 | 66 146 translate 2 setlinewidth 867 | 0 0 moveto gsave 0 500 moveto 500 0 rlineto stroke 868 | grestore 500 0 rlineto stroke 869 | showpage 870 | 871 | ==> Q3.ps <== 872 | %!PS-Adobe-3.0 EPSF-3.0 873 | %%BoundingBox: 55 145 557 647 874 | %%Pages: 1 875 | %%EndComments 876 | 66 146 translate 2 setlinewidth [500] 0 setdash 877 | 0 0 moveto 500 0 rlineto 0 500 rlineto -500 0 rlineto 878 | closepath stroke 879 | showpage 880 | 881 | ==> Q4.ps <== 882 | %!PS-Adobe-3.0 EPSF-3.0 883 | %%BoundingBox: 55 145 557 647 884 | %%Pages: 1 885 | %%EndComments 886 | 66 146 translate 2 setlinewidth [50] 0 setdash 887 | 0 0 moveto 500 0 rlineto stroke 888 | 500 500 moveto -500 0 rlineto stroke 889 | 500 0 moveto -500 0 rlineto stroke 890 | 0 500 moveto 500 0 rlineto stroke 891 | showpage 892 | 893 | ==> Q5.ps <== 894 | %!PS-Adobe-3.0 EPSF-3.0 895 | %%BoundingBox: 55 145 557 647 896 | %%Pages: 1 897 | %%EndComments 898 | 66 146 translate 2 setlinewidth [50] 0 setdash 899 | .2 setgray 0 0 moveto 500 0 rlineto stroke 900 | .4 setgray 500 500 moveto -500 0 rlineto stroke 901 | .6 setgray 500 0 moveto -500 0 rlineto stroke 902 | .8 setgray 0 500 moveto 500 0 rlineto stroke 903 | showpage 904 | 905 | ==> Q6.ps <== 906 | %!PS-Adobe-3.0 EPSF-3.0 907 | %%BoundingBox: 55 145 557 647 908 | %%Pages: 1 909 | %%EndComments 910 | 66 146 translate /B {bind def} dup exec /E {exch def} B 911 | /Box {/W E /H E moveto 912 | W 0 rlineto 0 H rlineto W neg 0 rlineto closepath} B 913 | 0 -1 2 500 Box 0 499 2 500 Box fill 914 | showpage 915 | 916 | ==> Q7.ps <== 917 | %!PS-Adobe-3.0 EPSF-3.0 918 | %%BoundingBox: 55 145 557 647 919 | %%Pages: 1 920 | %%EndComments 921 | 66 146 translate /B {bind def} dup exec /E {exch def} B 922 | /Box {/W E /H E moveto 923 | W 0 rlineto 0 H rlineto W neg 0 rlineto closepath} B 924 | 0 -1 502 500 Box fill 1 setgray 0 1 498 500 Box fill 925 | showpage 926 | 927 | ==> Q8.ps <== 928 | %!PS-Adobe-3.0 EPSF-3.0 929 | %%BoundingBox: 55 145 557 647 930 | %%Pages: 1 931 | %%EndComments 932 | 66 146 translate 2 setlinewidth [5] 0 setdash newpath 933 | 500 0 0 0 -500 0 500 500 -500 0 500 0 500 0 0 500 934 | 4 {moveto rlineto} bind repeat stroke 935 | showpage 936 | EndNotes 937 | showpage 938 | PageBottom 939 | %%EOF 940 | --------------------------------------------------------------------------------