wps

PostScript for the Web
git clone https://logand.com/git/wps.git/
Log | Files | Refs | LICENSE

commit ed6c91fe87a5316e691af991c4a1d551ee334d65
parent 6f9bd88894ebf146a8a1af7728545026aa3a5153
Author: tomas <tomas@logand.com>
Date:   Sat, 23 Jan 2010 14:48:41 +0100

Changes from 2009-06-30

Diffstat:
Mindex.org | 1895++++++++++++++++++++++++++++++++++++-------------------------------------------
1 file changed, 869 insertions(+), 1026 deletions(-)

diff --git a/index.org b/index.org @@ -1,285 +1,565 @@ -* Postscript interpreter +#+options: author:nil num:nil creator:nil timestamp:nil -- S :: stack -- F :: function dictionary +PostScript and PDF interpreter in JavaScript + +PostWeb \\ +WebScript + +TODO reuse parsed wps.wps + +QQQ + +Everything is interpreted. Compilation is translation to lower +abstraction level or precomputing. + +psi/z-matrix.c +Resource/Init/opdfread.ps + +* PostScript interpreter + +- stack +- function dictionary +- data types +- reader +- interpreter/evaluator +- native bindings (JavaScript FFI) +- PostScript and PDF API + +PDF is stateless? + +PostScript is stateful? + +#+begin_html +<style> +tt {background-color:#fdf} +canvas {width:12em;height:12em;border:1px dashed black} +/*canvas {width:10em;height:10em;border:1px dashed black;position:relative;top:0;left:0}*/ +</style> +#+end_html + +#+html: <div id="wps" style="display:none"> +#+include "wps.wps" src text +#+html: </div> +#+begin_html +<script type="text/javascript" src="wps.js"></script> +<script> +function $(Id) {return document.getElementById(Id);} +function $$(Id) {return $(Id).textContent;} +</script> +#+end_html ** Trivial example +#+html: <div id="example1"> +#+begin_src js2 +function example1() { + // define stack and operators + var Os = []; + var Sd = {}; + var Ds = [Sd]; + Sd["+"] = function() {Os.push(Os.pop() + Os.pop());}; + Sd["="] = function() {alert(Os.pop());}; + // compute 1 2 = 3 + = + Os.push(1); + Os.push(2); + Sd["="](); + Os.push(3); + Sd["+"](); + Sd["="](); +} +#+end_src +#+html: </div> #+begin_html <script> function ex1() { - var S = []; - var F = {}; - F["+"] = function() {S.push(S.pop() + S.pop());}; - F["."] = function() {alert(S.pop());}; - - S.push(1); - S.push(2); - F["."](); - S.push(2); - F["+"](); - F["."](); + eval($$("example1")); + example1(); } </script> <button onclick="javascript:ex1()">Eval</button> -"<tt>1 2 . 2 + .</tt>" from stack +"<tt>1 2 = 3 + =</tt>" from harcoded stack #+end_html -** Example with simple reader - +** Example with PostScript reader + +#+html: <div id="example2"> +#+begin_src js2 +function example2(T) { + var Os = []; + var Sd = {}; + var Ds = [Sd]; + var Es = []; + Sd["+"] = function() {Os.push(Os.pop() + Os.pop());}; + Sd["dup"] = function() {var X = Os.pop(); Os.push(X); Os.push(X);}; + Sd["="] = function() {alert(Os.pop());}; + ps0(T, Os, Ds, Es); // read and interpret code T +} +#+end_src +#+html: </div> #+begin_html <script> -function PdfT(V) { - this.V = V; - return this; -} -function isPdfT(V) { - return V.constructor == PdfT; // TODO better test +function ex2() { + eval($$("example2")); + example2($$("ex2")); } +</script> +<button onclick="javascript:ex2()">Eval</button> +"<tt id="ex2">12 34 + dup = 56 + =</tt>" from string +#+end_html -function ps(L, F, S) { - var N = L.length; - var I = 0; - if(!S) S = []; - - function member(C, L) {return 0 <= L.indexOf(C);} - function peek() {return I < N && L[I];} - function char() {return I < N && L[I++];} - function skip() {while(I < N && member(L[I], " \t\n")) I++;} - - function comment() { - while("%" == peek()) { - while(peek() && "\n" != peek()) - char(); - skip(); - } - } - - function text() { - char(); - var L = []; - var N = 1; - while(0 < N && peek()) { - var C = char(); - switch(C) { - case "(": - N++; - break; - case ")": - N--; - if(N <= 0) C = false; - break; - case "\\": - C = char(); - switch(C) { - case "(": break; - case ")": break; - case "\\": break; - case "n": C = "\n"; break; - case "r": C = "\r"; break; - case "t": C = "\t"; break; - default: - C = false; - } - break; - } - if(C !== false) L.push(C); - } - return new PdfT(L.join("")); - } - - function symbol() { - var C = char(); - var N = member(C, "+-0123456789."); - var F = "." == C; - var L = [C]; - while(peek() && !member(peek(), "%/[]{}<>( \t\n")) { - C = char(); - L.push(C); - if(N && !member(C, "0123456789")) { - if(!F && "." == C) F = true; - else N = false; - } - } - L = L.join(""); - if(1 == L.length && member(L, "+-.")) N = false; - return N ? (F ? parseFloat(L) : parseInt(L, 10)) : L; - } - - function code() { - char(); - var L = []; - while(peek()) { - var T = token(); - if("}" == T) break; - if(T || T == 0) L.push(T); - } - return L; - } - - function token() { - skip(); - switch(peek()) { - case false: return undefined; - case "%": return comment(); - case "[": return char(); - case "]": return char(); - case "{": return code(); - case "}": return char(); - case "(": return text(); - default: return symbol(); - } - } - -// function quoted(T) { -// return typeof T == "string" && "/" == T.charAt(0); -// } - - function parse(E) { - var G = true; - while(G && peek()) { - var T = token(); - if(T || T == 0) { - if(typeof T == "number" || typeof T == "object" || quoted(T)) - S.push(T); - else { - if(F[T]) F[T](); - else throw "Unknown operator '" + T + "' " + typeof T; - if(E == T) G = false; - } - } - } - return S; - } - - return parse(); -} +** Example with recursion + +#+html: <div id="example3"> +#+begin_src ps +% based on the example from +% http://en.literateprograms.org/Fibonacci_numbers_(PostScript) +% 0, 1, 1, 2, 3, 5, 8, 13, 21 + +%0.1 1.2 2.3 4.5 3 {pstack} repeat +%0.1 1.2 2.3 4.5 3 {pstack} .repeat + +%/fibonacci{0.1 1.2 2.3 4.5 pstack 3{pstack}repeat pstack}def +%fibonacci + +%/fibonacci{0.1 1.2 2.3 4.5 3{1 add pstack}repeat}def +%fibonacci + +%0 1 1 4 {add} for pstack clear % 10 +%1 2 6 { } for pstack clear % 1 3 5 +%3 -.5 1 { } for pstack clear % 3.0 2.5 2.0 1.5 1.0 + +4 {(abc)} repeat pstack clear % (abc) (abc) (abc) (abc) +1 2 3 4 3 {pop} repeat pstack clear % 1 % Pops 3 values (down to the 1) +4 { } repeat pstack clear % % Does nothing four times +mark 0 {(will not happen)} repeat pstack clear % mark + +%false false or = +%true false or = +%false true or = +%true true or = + +% from http://www.math.ubc.ca/~cass/graphics/manual/pdf/ch9.pdf + +/factorial { 1 dict begin + /n exch def + n 0 eq { + 1 + }{ + n n 1 sub factorial mul + } ifelse +end } def + +%5 factorial pstack clear + +% args: array a of numbers +% effect: sorts the array in order +/bubblesort { 4 dict begin + /a exch def + /n a length 1 sub def +n 0 gt { + % at this point only the n+1 items in the bottom of a remain to be sorted + % the largest item in that block is to be moved up into position n + n { + 0 1 n 1 sub { + /i exch def + a i get a i 1 add get gt { + % if a[i] > a[i+1] swap a[i] and a[i+1] + a i 1 add + a i get + a i a i 1 add get + % set new a[i] = old a[i+1] + put + % set new a[i+1] = old a[i] + put + } if + } for + /n n 1 sub def + } repeat +} if +end } def + +%[5 4 3 2 1 0] bubblesort pstack clear + +%{1 2 add {2 mul}} pstack exec pstack exec pstack clear + +%1 2 1 {add {(hi)} dup} repeat pstack clear +%1 2 {} pstack clear +%1 2 {} exec pstack clear + +%(de repeat (N . B) +% (when (gt0 N) +% (run B 1) ) +% (when (< 1 N) +% (repeat (- N 1) B) ) ) + +%/fibonacci { % n -- +% 1 sub +% 1 1 3 2 roll +% { 2 copy add 3 2 roll pop pstack} repeat +%} bind def + +%0 fibonacci = % 0 +%1 fibonacci = % 1 +%2 fibonacci = % 1 +%6 fibonacci = % 8 + + +% http://en.wikibooks.org/wiki/Transwiki:Fibonacci_number_program#PostScript + +%/fib1 { +% 1 dup +% 3 -1 roll { +% dup +% 3 -1 roll +% dup +% 4 1 roll +% add +% 3 -1 roll +% } repeat +%} def + +%5 fib1 pstack clear + +/fib2 { + dup dup 1 eq exch 0 eq or not { + dup 1 sub fib2 + exch 2 sub fib2 + add + } if +} def -function quoted(T) { - return typeof T == "string" && "/" == T.charAt(0); -} +%5 fib2 pstack clear +#+end_src +#+html: </div> +#+begin_html +<script> +function ex3() {wps(null, [$$("wps"), $$("example3")]);} +</script> +<button onclick="javascript:ex3();">Eval</button> +#+end_html +* The interpreter + +A few initial ideas: + +- Learn and implement a Forth like language. PostScript seems a great choice: + - It has the right syntax and stack based evaluation. + - It is practical and widely used. + - It has long sucessful history in print and publishing. + - It is a predecessor of PDF. + - Almost everything (e.g. editors, pictures, documentation) can be + reused to a great extent. + - It is ideal for HTML 5 canvas experiments because from the + PostScript point of view, canvas is just another low level device. +- Flexibility and simplicity first. + - Optimize for fast change, not for raw running speed. Keep the + code small and regular if possible. + - Can JavaScript be used as a portable assembler for web? Is + building scripting languages on top of JavaScript feasible and + efficient enough for real-world use? If not, why? Find the + limits. +- Keep the language/environment specific core as small as possible. + - Allow to port the interpreter to other languages on both + client and server side. + - Be open for the possibility of running "the same code" on both the + client and server side. +- Can PDF documents be displayed in web browsers without server-side + image rendering? + - Implement a canvas based version of PDF page contents in [[http://ondoc.logand.com][OnDoc]]. +- Investigate the possibility of implementing a Lisp interpreter + suitable for production use in web applications. + +Operators beginning with dot are non-standard low level operators +which are subject to change. + +** PostScript data types + +| category | type | executable | example | spec | +|-----------+-------------+------------+------------------------+--------------------| +| simple | boolean | | true false | | +| | fontID | | | | +| | integer | | 42 -123 0 | | +| | mark | | | | +| | name | Y | draw /draw | | +| | null | | null | | +| | operator | Y | | | +| | real | | 3.14 1e-10 | | +| | save | | | | +| composite | array | Y | [1 /hi 3.14] {1 2 add} | | +| | condition | | | Display PostScript | +| | dictionary | | <</a 1/b 2>> | | +| | file | | | | +| | gstate | | | Level 2 | +| | lock | | | Display PostScript | +| | packedarray | | | Level 2 | +| | string | Y | (hi) <a33f> | | + +** Low level data types + +| category | type | direct | literal | executable | +|-----------+------------+--------+---------+------------| +| simple | boolean | Y | Y | - | +| | number | Y | Y | - | +| | mark | - | Y | - | +| | name | - | Y | Y | +| | null | Y | Y | - | +| | operator | Y | - | Y | +| composite | array | Y | Y | - | +| | proc | - | - | Y | +| | dictionary | Y | Y | - | +| | string | Y | Y | - | + +All types are represented directly in JavaScript except: + +| type | representation | +|-----------------+-----------------| +| mark | unique object | +| literal name | quoted symbol | +| executable name | unquoted symbol | +| operator | function | +| proc | quoted array | + +*** exec + +pop any, case: + +| type | result | +|-----------------+-------------------| +| executable name | exec value | +| operator | apply operator | +| proc | exec each element | + +otherwise push the original value + +*** cvx + +| from | to | how | +|--------------+-----------------+---------| +| literal name | executable name | unquote | +| array | proc | quote | +| string | proc | ~ parse | + +** Stack + + + +* Drawing with PostScript + +Measuring angles: + +| language/device | unit | +|-----------------+------| +| canvas | rad | +| PostScript | deg | +| PDF | rad | + +** Bowtie example + +#+html: <canvas id="xbowtie"></canvas> +#+html: <div id="bowtie"> +#+include "bowtie.wps" src ps +#+html: </div> +#+begin_html +<script> +wps($("xbowtie"), [$$("wps"), $$("bowtie")]); +</script> +#+end_html -var Msie = 0 < window.navigator.userAgent.indexOf("MSIE"); // :-( -if(!Msie && !HTMLElement.prototype.innerText) { - HTMLElement.prototype.__defineGetter__("innerText", - function () {return(this.textContent);}); - HTMLElement.prototype.__defineSetter__("innerText", - function(V) {this.textContent = V;}); -} +** Digital clock example -function ex2() { - var S = []; - var F = {}; - F["+"] = function() {S.push(S.pop() + S.pop());}; - F["dup"] = function() {var X = S.pop(); S.push(X); S.push(X);}; - F["."] = function() {alert(S.pop());}; - ps(document.getElementById("ex2").innerText, F, S); -} +#+html: <canvas id="xclock"></canvas> +#+html: <div id="clock"> +#+include "clock.wps" src ps +#+html: </div> +#+begin_html +<script> +wps($("xclock"), [$$("wps"), $$("clock")]); +</script> +#+end_html + +** Analog clock example + +#+html: <canvas id="xclock2"></canvas> + +Click on the clock to start/stop it. + +#+html: <div id="clock2"> +#+include "clock2.wps" src ps +#+html: </div> +#+begin_html +<script> +wps($("xclock2"), [$$("wps"), $$("clock2")]); </script> -<button onclick="javascript:ex2()">Eval</button> -"<tt id="ex2">12 34 + dup . 56 + .</tt>" from string #+end_html -#+begin_src text -{ /category (COOKING) } +** Tiger example -: sum -1 2 + ; +Text drawing in canvas is not working in Firefox and Opera, works in +Chrome. -1 (sdfsdf) /Tf +Firefox throws error about linecap and linejoin not being supported. +However, it does not throw error about missing support for text +drawing. -12 34 (cooking is fun) /Tf +#+plot: title:"tiger.eps drawing times" ind:1 deps:(2) type:2d with:histograms set:"yrange [0:]" set:"xlabel 'browser'" set:"ylabel 'time [s]'" set:"style histogram gap 1" file:"tiger.png" set:"term png size 400, 300" +| browser | time [s] | +|---------+----------| +| Chrome | 3.8 | +| Opera | 13.4 | +| Firefox | 19.5 | -{ /key (value) } -#+end_src +file:tiger.png -* PDF drawing +** Fern example +from http://www.pvv.ntnu.no/~andersr/fractal/PostScript.html -#+html: <div id="wps"> -#+include "wps.wps" src ps +#+html: <canvas id="xfern"></canvas> + +#+html: <div id="fern"> +#+include "fern.wps" src ps #+html: </div> +#+begin_html +<script> +//wps($("xfern"), [$$("wps"), $$("fern")]); +</script> +#+end_html -#+html: <div id="bowtie"> -#+include "bowtie.wps" src ps +** Tree example + +from http://www.pvv.ntnu.no/~andersr/fractal/PostScript.html + +#+html: <canvas id="xtree2"></canvas> + +#+html: <div id="tree2"> +#+include "tree2.ps" src ps #+html: </div> +#+begin_html +<script> +//wps($("xtree2"), [$$("wps"), $$("tree2")]); +</script> +#+end_html +** Other +1 0 0 0 setcmykcolor % 100% cyan \\ +0 0 1 0 setcmykcolor % 100% yellow +** Fill example +#+html: <canvas id="xfill"></canvas> +#+html: <div id="fill"> +#+include "fill.wps" src ps +#+html: </div> +#+begin_html +<script> +wps($("xfill"), [$$("wps"), $$("fill")]); +</script> +#+end_html + +** Chessboard example +#+html: <canvas id="xchess"></canvas> +#+html: <div id="chess"> +#+include "chess.eps" src ps +#+html: </div> #+begin_html -<pre id="ex3x"> -1 2.3 + -5.6 + . -</pre> -<pre id="ex3"> +<div id="ychess" style="display:none"> +0 0 180 180 .gbox +%1 0 0 -1 0 180 cm +</div> +<script> +wps($("xchess"), [$$("wps"), $$("ychess"), $$("chess")]); +</script> +#+end_html -%%% ps operators +* Drawing with PDF -/setlinewidth {/lineWidth gput} def +PDF documents have the origin of the coordinate system in the bottom +left corner while HTML 5 canvas int the top left corner. Thus, some +of the following pictures are displayed upside down (unless an +explicit coordinate transformation was added which is not part of the +visible example code). -/setlinecap {/lineCap gput} def +** Heart example -/setlinejoin {/lineJoin gput} def +#+html: <canvas id="xheart"></canvas> +#+html: <div id="heart"> +#+include "heart.wpdf" src ps +#+html: </div> +#+begin_html +<script> +wps($("xheart"), [$$("wps"), $$("heart")]); +</script> +#+end_html -/setmiterlimit {/miterLimit gput} def +** Rectangle example -/setgray {255 mul dup dup rgb /fillStyle gput} def +#+html: <canvas id="xrect"></canvas> +#+html: <div id="rect"> +#+include "rect.wpdf" src ps +#+html: </div> +#+begin_html +<script> +wps($("xrect"), [$$("wps"), $$("rect")]); +</script> +#+end_html -%%% examples +** Triangles example -1 0 0 -1 0 446 cm % 0,0 in bottom left corner +#+html: <canvas id="xtriangles"></canvas> +#+html: <div id="triangles"> +#+include "triangles.wpdf" src ps +#+html: </div> +#+begin_html +<script> +wps($("xtriangles"), [$$("wps"), $$("triangles")]); +</script> +#+end_html -% E1 +** Smile example -q -0 0 m 0 0 150 150 re f -q -0 150 255 rg -0 0 m 15 15 120 120 re f -q -255 255 255 rg -%0.5 alpha -0 0 m 30 30 90 90 re f -Q -0 0 m 45 45 60 60 re f -Q -0 0 m 60 60 30 30 re f -Q +#+html: <canvas id="xsmile"></canvas> +#+html: <div id="smile"> +#+include "smile.wpdf" src ps +#+html: </div> +#+begin_html +<script> +wps($("xsmile"), [$$("wps"), $$("smile")]); +</script> +#+end_html -% E2 +** Star example -q -255 0 0 rg -0 0 m 10 10 55 50 re f -0 0 200 rg -0 0 m 30 30 55 50 re f -Q +#+html: <canvas id="xstar"></canvas> +#+html: <div id="star"> +#+include "star.wpdf" src ps +#+html: </div> +#+begin_html +<script> +wps($("xstar"), [$$("wps"), $$("star")]); +</script> +#+end_html -% E3 +** Squares 2 example -q -1 0 0 -1 50 200 cm -0 0 0 rg -%BT -(serif) 24 Tf -%1 0 0 1 260 254 -(Hello World) Tj -%ET -Q +#+html: <canvas id="xsquares2"></canvas> +#+html: <div id="squares2"> +#+include "squares2.wpdf" src ps +#+html: </div> +#+begin_html +<script> +wps($("xsquares2"), [$$("wps"), $$("squares2")]); +</script> +#+end_html -q -0 0 255 rg -4 0 0 4 315 204 cm - 0 5.5 m --4 -5.5 l - 6 1 l --6 1 l - 4 -5.5 l -f -Q +** Junk + +#+begin_html +<pre> + +1 0 0 -1 0 446 cm % 0,0 in bottom left corner % Ex4 @@ -321,45 +601,8 @@ Q b Q -% E5 - -1 0 0 1 100 100 cm - -255 255 255 rg -75 50 m -100 75 l -100 25 l -f - -% http://developer.mozilla.org/samples/canvas-tutorial/2_2_canvas_moveto.html -%0 0 m -%75 75 50 0 pi 2 * true arc -%110 75 m -%75 75 35 0 pi false arc -%65 65 m -%60 65 5 0 pi 2 * true arc -%95 65 m -%90 65 5 0 pi 2 * true arc -%S - -% http://developer.mozilla.org/samples/canvas-tutorial/2_3_canvas_lineto.html - -1 0 0 1 100 100 cm - -25 25 m -105 25 l -25 105 l -f - -125 125 m -125 45 l -45 125 l -h S - % http://developer.mozilla.org/samples/canvas-tutorial/2_5_canvas_quadraticcurveto.html -1 0 0 1 100 100 cm - %75 25 m %25 25 25 62 5 c2 %25 100 50 100 c2 @@ -369,70 +612,12 @@ h S %125 25 75 25 c2 %S -q % heart (bezier) -1 0 0 -1 0 0 cm -255 0 0 rg -75 40 m -75 37 70 25 50 25 c -20 25 20 62.5 20 62.5 c -20 80 40 102 75 120 c -110 102 130 80 130 62.5 c -130 62.5 130 25 100 25 c -85 25 75 37 75 40 c -f -Q - - -/triangle { - 255 255 255 rg - 75 50 m - 100 75 l - 100 25 l - f -} def - -/triangle2 { - 255 0 255 rg - 75 50 m - 100 75 l - 100 25 l - f -} def - -triangle -1 0 0 1 100 -100 cm -triangle2 -1 0 0 1 100 -100 cm -triangle - %3 8 div 6 add . %6 3 8 div add . %8 7 3 mul sub . %7 3 mul 8 exch sub . -7.2 36.0 m -14.4 7.2 l -S -14.4 43.2 m -0 -21.6 l -S - -1 0 0 1 27.0 36.0 cm -0 72 m -72 0 l -0 -72 l --72 0 l -4 setlinewidth -h S - -/pi 3.141592653589 def -%pi . -%pi 2 mul . - -/inch {72 mul} def -%5 inch . - /box { 0 0 m 72 0 l @@ -453,623 +638,46 @@ box % TODO not, and, or, xor % TODO for loop exit - -/factorial %stack: n --- n! (after) -{ dup 1 gt - {dup 1 sub factorial mul} if -} def - -%5 factorial . - -% https://developer.mozilla.org/samples/canvas-tutorial/4_1_canvas_fillstyle.html - -% for (i=0;i<6;i++){ -% for (j=0;j<6;j++){ -% ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' + -% Math.floor(255-42.5*j) + ',0)'; -% ctx.fillRect(j*25,i*25,25,25); - -%0 2 6 {.} for - -1 1 6 { %% i - dup 255 exch 255 6 div mul sub %% i ii - 1 1 6 { %% i ii j - dup 255 exch 255 6 div mul sub %% i ii j jj -% fillstyle -% fillrect 25 j mul | 25 i mul | 25 | 25 - } for -} for - - -% https://developer.mozilla.org/en/drawing_graphics_with_canvas - -/bowtie { % fillStyle - 200 200 200 0.3 rgba /fillStyle gput - -30 -30 60 60 fillRect - /fillStyle gput - 1.0 /globalAlpha gput - newpath - 25 25 moveto - -25 -25 lineto - 25 -25 lineto - -25 25 lineto - closepath - fill -} def - -/dot { - gsave - (black) /fillStyle gput - -2 -2 4 4 fillRect - grestore -} def - -0 -100 translate - -45 45 translate - -gsave -(red) bowtie -dot -grestore - -gsave -85 0 translate -45 pi mul 180 div rotate -(green) bowtie -dot -grestore - -gsave -0 85 translate -135 pi mul 180 div rotate -(blue) bowtie -dot -grestore - -gsave -85 85 translate -90 pi mul 180 div rotate -(yellow) bowtie -dot -grestore - - - - - - - - - - - - - - - - </pre> +#+end_html -<script> -function min(X, Y) { - return X < Y ? X : Y; -} - -function max(X, Y) { - return X < Y ? Y : X; -} +/MediaBox [0 0 612 446] -function ex3() { - var S = []; - var F = {}; - var W = document.getElementById("c"); - var C = W.getContext("2d"); - - W.setAttribute("width", 612); - W.setAttribute("height", 446); - - // basic operators - - F["neg"] = function() {S.push(- S.pop());}; - F["add"] = function() {S.push(S.pop() + S.pop());}; - F["sub"] = function() {F["neg"](); F["add"]();}; - F["mul"] = function() {S.push(S.pop() * S.pop());}; - F["div"] = function() { - var X = S.pop(); - S.push(S.pop() / X); - }; - F["idiv"] = function() { - var X = S.pop(); - S.push(Math.floor(S.pop() / X)); - }; - F["mod"] = function() { - var X = S.pop(); - S.push(S.pop() % X); - }; - // TODO sqrt, exp, ceiling, sin - F["exch"] = function() { - var Y = S.pop(); - var X = S.pop(); - S.push(Y); - S.push(X); - }; - - F["dup"] = function() {var X = S.pop(); S.push(X); S.push(X);}; - F["clear"] = function() {S = [];}; - F["pop"] = function() {S.pop();}; - // TODO roll - - F["eq"] = function() { - var Y = S.pop(); - var X = S.pop(); - S.push(X == Y); - }; - F["ne"] = function() { - var Y = S.pop(); - var X = S.pop(); - S.push(X != Y); - }; - F["gt"] = function() { - var Y = S.pop(); - var X = S.pop(); - S.push(X > Y); - }; - F["lt"] = function() { - var Y = S.pop(); - var X = S.pop(); - S.push(X < Y); - }; - F["ge"] = function() { - var Y = S.pop(); - var X = S.pop(); - S.push(X >= Y); - }; - F["le"] = function() { - var Y = S.pop(); - var X = S.pop(); - S.push(X <= Y); - }; - - F["if"] = function() { - var B = S.pop(); - var C = S.pop(); - if(C == true) run(B); - }; - F["ifelse"] = function() { - var N = S.pop(); - var P = S.pop(); - var C = S.pop(); - if(C == true) run(P); - else run(N); - }; - F["repeat"] = function() { - var B = S.pop(); - var N = S.pop(); - for(var I = 0; I < N; I++) run(B); - }; - F["for"] = function() { - var B = S.pop(); - var L = S.pop(); - var K = S.pop(); - var J = S.pop(); - if(K < 0) { - for(var I = J; L <= I; I += K) { - S.push(I); - run(B); - } - } else { - for(var I = J; I <= L; I += K) { - S.push(I); - run(B); - } - } - }; - - F["."] = function() {alert(S.pop());}; - F["=="] = function() {alert(S[0]);}; - F["pstack"] = function() {alert(S);}; - - function run(C) { - if(!C.length) S.push(C); - else { - var M = C.length; - for(var I = 0; I < M; I++) { - var T = C[I]; - if(typeof T == "number" || typeof T == "object" || quoted(T)) - S.push(T); - else { - if(F[T]) F[T](); - else throw "Unknown operator '" + T + "' " + typeof T; - } - } - } - } - - F["def"] = function() { - var C = S.pop(); - var N = S.pop(); - if(quoted(N)) F[N.substring(1)] = function() {run(C);} - else throw "Wrong operator name " + N; - }; - - // html5 graphic operators - - //transform - //setTransform - //createLinearGradient - //createRadialGradient - //createPatternI - //createPatternC - //createPatternV - F["clearRect"] = function() { - var H = S.pop(); - var W = S.pop(); - var Y = S.pop(); - var X = S.pop(); - C.clearRect(X, Y, W, H); - }; - F["fillRect"] = function() { - var H = S.pop(); - var W = S.pop(); - var Y = S.pop(); - var X = S.pop(); - C.fillRect(X, Y, W, H); - }; - F["strokeRect"] = function() { - var H = S.pop(); - var W = S.pop(); - var Y = S.pop(); - var X = S.pop(); - C.strokeRect(X, Y, W, H); - }; - //quadraticCurveTo - F["rect"] = function() { - var H = S.pop(); - var W = S.pop(); - var Y = S.pop(); - var X = S.pop(); - C.strokeRect(X, Y, W, H); - }; - //isPointInPath - //fillText - //strokeText - //measureText - //drawImageI1 - //drawImageI2 - //drawImageC1 - //drawImageC2 - //drawImageV1 - //drawImageV2 - //createImageData1 - //createImageData2 - //getImageData - //putImageData - - // html5 utility operators - - F["gput"] = function() { - var K = S.pop(); - var V = S.pop(); - C[K.substring(1)] = isPdfT(V) ? V.V : V; - }; - F["gget"] = function() { - var K = S.pop(); - S.push(C[K.substring(1)]); - }; - - F["rgb"] = function() { - var B = S.pop(); - var G = S.pop(); - var R = S.pop(); - S.push(new PdfT("rgba(" + R + "," + G + "," + B + ")")); - }; - F["rgba"] = function() { - var A = S.pop(); - var B = S.pop(); - var G = S.pop(); - var R = S.pop(); - S.push(new PdfT("rgba(" + R + "," + G + "," + B + "," + A + ")")); - }; - - // ps graphic operators - - F["gsave"] = function() {C.save();}; - F["grestore"] = function() {C.restore();}; - F["scale"] = function() { - var Y = S.pop(); - var X = S.pop(); - C.scale(X, Y); - }; - F["rotate"] = function() { - var A = S.pop(); - C.rotate(A); - }; - F["translate"] = function() { - var Y = S.pop(); - var X = S.pop(); - C.translate(X, Y); - }; - F["newpath"] = function() {C.beginPath();}; - F["closepath"] = function() {C.closePath();}; - F["moveto"] = function() { - var Y = S.pop(); - var X = S.pop(); - C.moveTo(X, Y); - }; - F["lineto"] = function() { - var Y = S.pop(); - var X = S.pop(); - C.lineTo(X, Y); - }; - F["arcto"] = function() { - var R = S.pop(); - var Y2 = S.pop(); - var X2 = S.pop(); - var Y1 = S.pop(); - var X1 = S.pop(); - C.arcTo(X1, Y1, X2, Y2, R); - }; - F["arc"] = function() { - var A = S.pop(); - var E = S.pop(); - var S = S.pop(); - var R = S.pop(); - var Y = S.pop(); - var X = S.pop(); - C.arc(X, Y, R, S, E, A); - }; - F["fill"] = function() {C.fill();}; - F["stroke"] = function() {C.stroke();}; - F["clip"] = function() {C.clip();}; - - // pdf graphic operators - - F["w"] = function() {C.lineWidth = S.pop();}; - F["J"] = function() {C.lineCap = S.pop();}; - F["j"] = function() {C.lineJoin = S.pop();}; - F["M"] = function() {C.mitterLimit = S.pop();}; - F["d"] = function() { - var P = S.pop(); - var A = S.pop(); - alert("TODO d"); - }; - F["ri"] = function() {alert("TODO ri");}; - F["i"] = function() {alert("TODO i");}; - F["gs"] = function() {alert("TODO gs");}; - - F["q"] = function() {C.save();}; - F["Q"] = function() {C.restore();}; - F["cm"] = function() { // TODO fix cm - var Dy = S.pop(); - var Dx = S.pop(); - var M22 = S.pop(); - var M21 = S.pop(); - var M12 = S.pop(); - var M11 = S.pop(); - //alert(M11 +"|"+ M12 +"|"+ M21 +"|"+ M22 +"|"+ Dx +"|"+ Dy); - //C.setTransform(M11, M12, M21, M22, Dx, Dy); - C.transform(M11, M12, M21, M22, Dx, Dy); - }; - - F["m"] = function() { - var Y = S.pop(); - var X = S.pop(); - C.beginPath(); // TODO only if not m previously - C.moveTo(X, Y); - }; - F["l"] = function() { - var Y = S.pop(); - var X = S.pop(); - C.lineTo(X, Y); - }; - F["c"] = function() { - var Y3 = S.pop(); - var X3 = S.pop(); - var Y2 = S.pop(); - var X2 = S.pop(); - var Y1 = S.pop(); - var X1 = S.pop(); - C.bezierCurveTo(X1, Y1, X2, Y2, X3, Y3); // TODO the right c method - }; -// F["c2"] = function() { // not in pdf -// var Y3 = S.pop(); -// var X3 = S.pop(); -// var Y2 = S.pop(); -// var X2 = S.pop(); -// var Y1 = S.pop(); -// var X1 = S.pop(); -// C.bezierCurveTo(X1, Y1, X2, Y2, X3, Y3); // TODO the right c method +#+begin_html +<script> +function xreq(Url, Cb, Er) { +// var req = new XMLHttpRequest(); +// alert(Url); +// req.open('GET', Url, true); +// req.onreadystatechange = function (e) { +// if(req.readyState == 4) { +// if(req.status == 200) Cb(req.responseText); +// else if(Er) Er(); +// } // }; - F["v"] = function() {alert("TODO v");}; - F["y"] = function() {alert("TODO y");}; - F["h"] = function() {C.closePath();}; - F["re"] = function() { - var Y2 = S.pop(); - var X2 = S.pop(); - var Y1 = S.pop(); - var X1 = S.pop(); - C.rect(X1, Y1, X2, Y2); - }; - - F["S"] = function() {C.stroke();}; - F["s"] = function() {F["h"](); F["S"]();}; - F["f"] = function() {C.fill();}; - F["F"] = function() {C.fill();}; - F["f*"] = function() {alert("TODO f*");}; - F["B"] = function() {F["f"](); F["S"]();}; - F["B*"] = function() {F["f*"](); F["S"]();}; - F["b"] = function() {F["h"](); F["B"]();}; - F["b*"] = function() {F["h"](); F["B*"]();}; - F["n"] = function() {alert("TODO n");}; - - F["W"] = function() {C.clip();}; - F["W*"] = function() {alert("TODO W*");}; - - F["BT"] = function() {alert("TODO BT")}; - F["ET"] = function() {alert("TODO ET")}; - - F["Tc"] = function() {alert("TODO Tc");}; - F["Tw"] = function() {alert("TODO Tw");}; - F["Tz"] = function() {alert("TODO Tz");}; - F["TL"] = function() {alert("TODO Tf");}; - F["Tf"] = function() { - var N = S.pop(); - var F = S.pop(); - C.font = N + "pt " + F.V; - }; - F["Tr"] = function() {alert("TODO Tr");}; - F["Ts"] = function() {alert("TODO Ts");}; - - F["Td"] = function() {alert("TODO Td");}; - F["TD"] = function() {alert("TODO TD");}; - F["Tm"] = function() {alert("TODO Tm");}; - F["T*"] = function() {alert("TODO T*");}; - - F["Tj"] = function() { - var T = S.pop(); - //alert(T.V); - //if(C.strokeText) C.strokeText(T.V, 0, 0); - if(C.fillText) C.fillText(T.V, 0, 0); - }; - F["TJ"] = function() {alert("TODO TJ");}; - F["'"] = function() {alert("TODO '");}; - F["\""] = function() {alert("TODO \"");}; - - F["d0"] = function() {alert("TODO d0");}; - F["d1"] = function() {alert("TODO d1");}; - - F["CS"] = function() {alert("TODO CS");}; - F["cs"] = function() {alert("TODO cs");}; - F["SC"] = function() {alert("TODO SC");}; - F["SCN"] = function() {alert("TODO SCN");}; - F["sc"] = function() {alert("TODO sc");}; - F["scn"] = function() {alert("TODO scn");}; - F["G"] = function() {alert("TODO G");}; - F["g"] = function() {alert("TODO g");}; - F["RG"] = function() {alert("TODO RG");}; - F["rg"] = function() { // TODO color spaces - var B = S.pop(); - var G = S.pop(); - var R = S.pop(); - C.fillStyle = "rgb(" + R + "," + G + "," + B + ")"; - }; - F["K"] = function() {alert("TODO K");}; - F["k"] = function() {alert("TODO k");}; - - F["sh"] = function() {alert("TODO sh");}; - - F["BI"] = function() {alert("TODO BI");}; - F["ID"] = function() {alert("TODO ID");}; - F["EI"] = function() {alert("TODO EI");}; - - F["Do"] = function() {alert("TODO Do");}; - - F["MP"] = function() {alert("TODO MP");}; - F["DP"] = function() {alert("TODO DP");}; - F["BMC"] = function() {alert("TODO BMC");}; - F["BDC"] = function() {alert("TODO BDC");}; - F["EMC"] = function() {alert("TODO EMC");}; - - F["BX"] = function() {alert("TODO BX");}; - F["EX"] = function() {alert("TODO EX");}; - - ps(document.getElementById("ex3").innerText, F, S); +// req.send(null); + + try {netscape.security.PrivilegeManager.enablePriviledge(priviledge);} + catch(e) {} + var req = new XMLHttpRequest(); + req.open('GET', Url, false); + req.send(null); + if(req.status == 200) Cb(req.responseText); + else alert("uff"); } </script> -<button onclick="javascript:ex3()">Draw</button> #+end_html -/MediaBox [0 0 612 446] +#+html: <canvas id="c"></canvas> -#+html: <canvas id="c" style="width:612pt;height:446pt;background-color:yellow"/> +[[http://svn.ghostscript.com/viewvc/trunk/gs/examples/tiger.eps?view=co][tiger.eps]]: +#+html: <button onclick="javascript:xreq('http://svn.ghostscript.com/viewvc/trunk/gs/examples/tiger.eps?view=co', wps)">Draw</button> +#+html: <button onclick="javascript:xreq('file:///home/tomas/src/pdf4web/tiger.eps', alert)">Draw</button> -** CanvasRenderingContext2D +* JavaScript bindings http://www.whatwg.org/specs/web-apps/current-work/#the-canvas-element -Operators: - -| | category | operator | -|---+------------------------+----------| -| / | | < | -| | General graphics state | w | -| | | J | -| | | j | -| | | M | -| | | d | -| | | ri | -| | | i | -| | | gs | -| | Special graphics state | q | -| | | Q | -| | | cm | -| | Path construction | m | -| | | l | -| | | c | -| | | v | -| | | y | -| | | h | -| | | re | -| | Path painting | S | -| | | s | -| | | f | -| | | F | -| | | f* | -| | | B | -| | | B* | -| | | b | -| | | b* | -| | | n | -| | Clipping paths | W | -| | | W* | -| | Text objects | BT | -| | | ET | -| | Text state | Tc | -| | | Tw | -| | | Tz | -| | | TL | -| | | Tf | -| | | Tr | -| | | Ts | -| | Text positioning | Td | -| | | TD | -| | | Tm | -| | | T* | -| | Text showing | Tj | -| | | TJ | -| | | ' | -| | | " | -| | Type 3 fonts | d0 | -| | | d1 | -| | Color | CS | -| | | cs | -| | | SC | -| | | SCN | -| | | sc | -| | | scn | -| | | G | -| | | g | -| | | RG | -| | | rg | -| | | K | -| | | k | -| | Shading patterns | sh | -| | Inline images | BI | -| | | ID | -| | | EI | -| | XObjects | Do | -| | Marked content | MP | -| | | DP | -| | | BMC | -| | | BDC | -| | | EMC | -| | Compatibility | BX | -| | | EX | - -Special graphics state q, Q, cm 57 -Path construction m, l, c, v, y, h, re 59 - ??? rlineto rmoveto findfont scalefont setfont show rightshow stringwidth arcn loop/exit forall cvs array put get length aload astore mark ashow widthshow awidthshow kshow currentpoint makefont @@ -1084,108 +692,343 @@ octal chars in string \234 /Times-Roman findfont typography 15 scalefont setfont - -Methods: - -| | html5 | ps | pdf | method | -|---+----------------------+-----------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------| -| / | | | | < | -| | | gsave | q | void save(); | -| | | grestore | Q | void restore(); | -| | | scale | | void scale(in float x, in float y); | -| | | rotate | | void rotate(in float angle); | -| | | translate | | void translate(in float x, in float y); | -| | transform | | | void transform(in float m11, in float m12, in float m21, in float m22, in float dx, in float dy); | -| | setTransform | | cm ? | void setTransform(in float m11, in float m12, in float m21, in float m22, in float dx, in float dy); | -| | createLinearGradient | | | CanvasGradient createLinearGradient(in float x0, in float y0, in float x1, in float y1); | -| | createRadialGradient | | | CanvasGradient createRadialGradient(in float x0, in float y0, in float r0, in float x1, in float y1, in float r1); | -| | createPatternI | | | CanvasPattern createPattern(in HTMLImageElement image, in DOMString repetition); | -| | createPatternC | | | CanvasPattern createPattern(in HTMLCanvasElement image, in DOMString repetition); | -| | createPatternV | | | CanvasPattern createPattern(in HTMLVideoElement image, in DOMString repetition); | -| | clearRect | | | void clearRect(in float x, in float y, in float w, in float h); | -| | fillRect | | | void fillRect(in float x, in float y, in float w, in float h); | -| | strokeRect | | | void strokeRect(in float x, in float y, in float w, in float h); | -| | | newpath | m ! | void beginPath(); | -| | | closepath | h | void closePath(); | -| | | moveto | | void moveTo(in float x, in float y); | -| | | lineto | | void lineTo(in float x, in float y); | -| | quadraticCurveTo | | | void quadraticCurveTo(in float cpx, in float cpy, in float x, in float y); | -| | | | c | void bezierCurveTo(in float cp1x, in float cp1y, in float cp2x, in float cp2y, in float x, in float y); | -| | | arcto | | void arcTo(in float x1, in float y1, in float x2, in float y2, in float radius); | -| | rect | | | void rect(in float x, in float y, in float w, in float h); | -| | | arc | | void arc(in float x, in float y, in float radius, in float startAngle, in float endAngle, in boolean anticlockwise); | -| | | fill | f | void fill(); | -| | | | F ! | | -| | | stroke | S | void stroke(); | -| | | | s ! | | -| | | | b ! | | -| | | | b* ! | | -| | | clip | W | void clip(); | -| | | | W* ! | | -| | isPointInPath | | | boolean isPointInPath(in float x, in float y); | -| | fillText | | | void fillText(in DOMString text, in float x, in float y, [Optional] in float maxWidth); | -| | strokeText | | | void strokeText(in DOMString text, in float x, in float y, [Optional] in float maxWidth); | -| | measureText | | | TextMetrics measureText(in DOMString text); | -| | drawImageI1 | | | void drawImage(in HTMLImageElement image, in float dx, in float dy, [Optional] in float dw, in float dh); | -| | drawImageI2 | | | void drawImage(in HTMLImageElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh); | -| | drawImageC1 | | | void drawImage(in HTMLCanvasElement image, in float dx, in float dy, [Optional] in float dw, in float dh); | -| | drawImageC2 | | | void drawImage(in HTMLCanvasElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh); | -| | drawImageV1 | | | void drawImage(in HTMLVideoElement image, in float dx, in float dy, [Optional] in float dw, in float dh); | -| | drawImageV2 | | | void drawImage(in HTMLVideoElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh); | -| | createImageData1 | | | ImageData createImageData(in float sw, in float sh); | -| | createImageData2 | | | ImageData createImageData(in ImageData imagedata); | -| | getImageData | | | ImageData getImageData(in float sx, in float sy, in float sw, in float sh); | -| | putImageData | | | void putImageData(in ImageData imagedata, in float dx, in float dy, [Optional] in float dirtyX, in float dirtyY, in float dirtyWidth, in float dirtyHeight); | - -Attributes: - -| | html5 | ps | pdf | attribute | default | -|---+--------------------------+-----------------+-----+----------------------------------------------------------------------------------------------+-------------------| -| / | < | < | < | < | < | -| | globalAlpha | | | float globalAlpha; | 1.0 | -| | globalCompositeOperation | | | DOMString globalCompositeOperation; | source-over | -| | strokeStyle | (~setdash?) | | any strokeStyle; | black | -| | fillStyle | | | any fillStyle; | black | -| | lineWidth | ~ setlinewidth | | float lineWidth; | 1 | -| | lineCap | ~ setlinecap | | DOMString lineCap; // "butt", "round", "square" | butt | -| | lineJoin | ~ setlinejoin | | DOMString lineJoin; // "round", "bevel", "miter" | miter | -| | miterLimit | ~ setmiterlimit | | float miterLimit; | 10 | -| | shadowOffsetX | | | float shadowOffsetX; | 0 | -| | shadowOffsetY | | | float shadowOffsetY; | 0 | -| | shadowBlur | | | float shadowBlur; | 0 | -| | shadowColor | | | DOMString shadowColor; | transparent black | -| | font | | | DOMString font; | 10px sans-serif | -| | textAlign | | | DOMString textAlign; // "start", "end", "left", "right", "center" | start | -| | textBaseline | | | DOMString textBaseline; // "top", "hanging", "middle", "alphabetic", "ideographic", "bottom" | alphabetic | - - -#+begin_src idl -interface CanvasGradient { - // opaque object - void addColorStop(in float offset, in DOMString color); -}; - -interface CanvasPattern { - // opaque object -}; - -interface TextMetrics { - readonly attribute float width; -}; - -interface ImageData { - readonly attribute unsigned long width; - readonly attribute unsigned long height; - readonly attribute CanvasPixelArray data; -}; - -[IndexGetter, IndexSetter] -interface CanvasPixelArray { - readonly attribute unsigned long length; -}; -#+end_src +** Built-in operators + +| category | in | operator | out | +|----------------+-------------------------+----------+-------------------------------------------------------------| +| Trivial | | true | true | +| | | false | false | +| | | null | null | +| Math | x | neg | -x | +| | x y | add | x+y | +| | x y | mul | x*y | +| | x y | div | x/y | +| | x y | mod | x%y | +| Stack | | mark | mark | +| | x y | exch | y x | +| | | clear | | +| | x | pop | | +| | any_n ...any_0 n | index | any_n ... any_0 any_n | +| | any_(n-1) ... any_0 n j | roll | any_((j-1) mod n) ... any_0 ... any_(n-1) ... any_(j mod n) | +| | any_1 ... any_n n | copy | any_1 ... any_n any_1 ... any_n | +| Array | array | length | n | +| Conditionals | x y | eq | bool | +| | x y | lt | bool | +| | y | not | bool | +| | x y | and | z | +| | x y | or | z | +| | bool then else | ifelse | | +| | n proc | repeat | | +| | i j k proc | for | | +| Debugging | x | . | | +| | | pstack | | +| Dictionaries | n | dict | dict | +| | dict key | get | any | +| | dict key any | put | | +| | sym proc | def | | +| Arrays | n | array | array | +| JavaScript FFI | dict key nargs | .call | any | +| | | .gc | gc | +| | | .math | Math | +| HTML 5 | r g b | .rgb | text | +| | r g b a | .rgba | text | + +** Core operators + +| category | in | operator | out | +|--------------+-------------+-------------+--------| +| Math | | abs | | +| | | .acos | | +| | | .asin | | +| | | atan | | +| | | .atan2 | | +| | | ceiling | | +| | | cos | | +| | | .exp | | +| | | floor | | +| | | log | | +| | | .max | | +| | | .min | | +| | | .pow | | +| | | .random | | +| | | rand | | +| | | round | | +| | | sin | | +| | | sqrt | | +| | | .tan | | +| | | truncate | | +| | | .e | | +| | | .ln2 | | +| | | .ln10 | | +| | | .log2e | | +| | | .log10e | | +| | | .pi | | +| | | .sqrt1_2 | | +| | | .sqrt2 | | +| | | sub | | +| | | idiv | | +| Stack | x | dup | x x | +| Conditionals | x y | ne | bool | +| | x y | ge | bool | +| | x y | le | bool | +| | x y | gt | bool | +| | bool proc | if | | +| HTML 5 | key | .gget | | +| | any key | .gput | | +| | key nargs | .gcall0 | | +| | key nargs | .gcall1 | | +| | | .gcanvas | canvas | +| | w h | .gdim | | +| | x0 y0 x1 y1 | .gbox | | +| PostScript | gray | setgray | | +| | r g b | setrgbcolor | | +| | ??? | setfont ? | | +| | | clippath ? | | +| | text | show ? | | +| | x y | rlineto | | + +** Canvas methods + +| | in | canvas | out | ps | pdf | +|---+----------------------------------------------+-----------------------+----------------+------------+-------------| +| / | | | | < | < | +| | | .save | | gsave | q | +| | | .restore | | grestore | Q | +| | x y | scale | | scale | - | +| | angle | rotate | | rotate | - | +| | x y | translate | | translate | - | +| | m11 m12 m21 m22 dx dy | .transform | | - | cm | +| | m11 m12 m21 m22 dx dy | .setTransform | | - | - | +| | x0 y0 x1 y1 | .createLinearGradient | canvasGradient | | | +| | x0 y0 r0 x1 y1 r1 | .createRadialGradient | canvasGradient | | | +| | image repetition | .createPattern | canvasPattern | | | +| | x y w h | .clearRect | | rectclip | | +| | x y w h | .fillRect | | rectfill | | +| | x y w h | .strokeRect | | rectstroke | | +| | | .beginPath | | newpath | m ? | +| | | .closePath | | closepath | ~ h ? ~ n ? | +| | x y | .moveTo | | moveto | m ? | +| | x y | .lineTo | | lineto | l | +| | cpx cpy x y | .quadraticCurveTo | | | | +| | cp1x cp1y cp2x cp2y x y | .bezierCurveTo | | | c | +| | x1 y1 x2 y2 radius | .arcTo | | arcto | | +| | x y w h | .rect | | - | ~ re | +| | x y radius startAngle endAngle anticlockwise | .arc | | ~ arc | | +| | | fill | | fill | ~ f ? | +| | | stroke | | stroke | S | +| | | clip | | clip | ~ W ? | +| | x y | .isPointInPath | boolean | | | +| | text x y | .fillText1 | | | | +| | text x y maxWidth | .fillText2 | | | | +| | text x y | .strokeText1 | | | | +| | text x y maxWidth | .strokeText2 | | | | +| | text | .measureText | textMetrics | | | +| | image dx dy | .drawImage1 | | | | +| | image dx dy dw dh | .drawImage2 | | | | +| | image sx sy sw sh dx dy dw dh | .drawImage3 | | | | +| | imagedata | .createImageData1 | imageData | | | +| | sw sh | .createImageData1 | imageData | | | +| | sx sy sw sh | .getImageData | imageData | | | +| | imagedata dx dy | .putImageData1 | | | | +| | imagedata dx dy dirtyX dirtyY dirtyW dirtyH | .putImageData2 | | | | + +** Canvas attributes + +| | type | attribute | values | ps | pdf | +|---+------+---------------------------+----------------------------------------------------+---------------+-------| +| / | | < | | < | < | +| | num | .globalAlpha | (1.0) | | | +| | str | .globalCompositeOperation | (source-over) | | | +| | any | .strokeStyle | (black) | ~ setdash ? | ~ d ? | +| | any | .fillStyle | (black) | | | +| | num | .lineWidth | (1) | setlinewidth | w | +| | str | .lineCap | (butt) round square | ~ setlinecap | J | +| | str | .lineJoin | round bevel (miter) | ~ setlinejoin | j | +| | num | .miterLimit | (10) | setmiterlimit | M | +| | num | .shadowOffsetX | (0) | | | +| | num | .shadowOffsetY | (0) | | | +| | num | .shadowBlur | (0) | | | +| | str | .shadowColor | (transparent black) | | | +| | str | .font | (10px sans-serif) | | | +| | str | .textAlign | (start) end left right center | | | +| | str | .textBaseline | top hanging middle (alphabetic) ideographic bottom | | | + +** Other operators + +| | canvas | ps | pdf | +|---+---------------------------------------------+----+-----| +| / | < | | | +| | canvasGradient offset color *.addColorStop* | | | + +** Other attributes + +| | dict | type | attribute | values | ps | pdf | +|---+------------------+------------------+-----------+--------+----+-----| +| / | | | < | | < | < | +| | textMetrics | num | width | | | | +| | imageData | cnt | width | | | | +| | imageData | cnt | heigth | | | | +| | imageData | canvasPixelArray | data | | | | +| | canvasPixelArray | cnt | length | | | | + +[IndexGetter, IndexSetter] CanvasPixelArray + +** PostScript operators + +| | category | in | operator | out | +|---+----------+---------+------------+-----| +| / | | < | < | < | +| | | x y [m] | transform | x y | +| | | x y [m] | itransform | x y | + +** PDF operators + +| | category | operator | | +|---+------------------------+----------+-----------------------------------------------------------| +| / | | < | | +| | General graphics state | w | setlinewidth | +| | | J | ~ setlinecap | +| | | j | ~ setlinejoin | +| | | M | setmiterlimit | +| | | d | ~ setdash ? | +| | | ri | {SetColorRenderingIntent} | +| | | i | {1 .min setflat} | +| | | gs | {SetExtGState} | +| | Special graphics state | q | gsave | +| | | Q | grestore | +| | | cm | .transform { //TempMatrix astore concat } | +| | Path construction | m | moveto | +| | | l | lineto | +| | | c | .bezierCurveTo (curveto) | +| | | v | ! currentpoint cp2 p3 c { currentpoint 6 2 roll curveto } | +| | | y | ! cp1 p3 p3 c { 2 copy curveto } | +| | | h | closepath | +| | | re | ! x y m , x+w y l , x+w y+h l , x y+h l , h | +| | Path painting | S | stroke | +| | | s | h S | +| | | f | (fill) | +| | | F | f | +| | | f* | {eofill} | +| | | B | f S { gsave fill grestore stroke } | +| | | B* | f* S { gsave eofill grestore stroke } | +| | | b | h b { closepath gsave fill grestore stroke } | +| | | b* | h B* { closepath gsave eofill grestore stroke } | +| | | n | {newpath} | +| | Clipping paths | W | clip | +| | | W* | {eoclip} | +| | Text objects | BT | | +| | | ET | {grestore} | +| | Text state | Tc | | +| | | Tw | | +| | | Tz | | +| | | TL | | +| | | Tf | | +| | | Tr | | +| | | Ts | | +| | Text positioning | Td | | +| | | TD | | +| | | Tm | | +| | | T* | | +| | Text showing | Tj | ~ show | +| | | TJ | | +| | | ' | | +| | | " | | +| | Type 3 fonts | d0 | setcharwidth | +| | | d1 | setcachedevice | +| | Color | CS | | +| | | cs | | +| | | SC | | +| | | SCN | | +| | | sc | | +| | | scn | | +| | | G | g | +| | | g | setgray | +| | | RG | rg | +| | | rg | setrgbcolor | +| | | K | k | +| | | k | setcmykcolor | +| | Shading patterns | sh | | +| | Inline images | BI | | +| | | ID | | +| | | EI | | +| | XObjects | Do | | +| | Marked content | MP | | +| | | DP | | +| | | BMC | | +| | | BDC | | +| | | EMC | | +| | Compatibility | BX | | +| | | EX | | + +* References + +** PostScript in JavaScript by others + +Somebody before: http://www.feiri.de/pcan/ RPN calculator with many +PostScript operators implemented directly in JavaScript. Fast drawing +but not "real" PostScript. + +Wish list: http://svgkit.sourceforge.net/ + +** Interesting PostScript applications + +http://starynkevitch.net/Basile/NeWS_descr_oct_1993.html \\ +http://www.art.net/studios/Hackers/Hopkins/Don/hyperlook/index.html \\ +http://books.google.com/books?id=xHSoK66z34YC&pg=PA193 \\ +http://www.art.net/studios/Hackers/Hopkins/Don/lang/NeWS.html \\ +http://en.wikipedia.org/wiki/Display_PostScript + +** Mess http://canvaspaint.org/blog/2006/12/rendering-text/ \\ http://dev.opera.com/articles/view/html-5-canvas-the-basics/ \\ http://www.benjoffe.com/code/ \\ http://arapehlivanian.com/wp-content/uploads/2007/02/canvas.html + +http://two.pairlist.net/pipermail/reportlab-users/2002-September/000599.html + +http://www.capcode.de/help/put ref \\ +http://www.math.ubc.ca/~cass/courses/ps.html ps operator summary \\ +http://atrey.karlin.mff.cuni.cz/~milanek/PostScript/Reference/PSL2d.html \\ +http://gauss.upf.es/www-storage/PS_Guide-1.0/operators.html \\ +http://web.mit.edu/ghostscript/www/Language.htm \\ +http://pages.cs.wisc.edu/~ghost/doc/gnu/7.05/Ps-style.htm \\ +http://www.tailrecursive.org/postscript/operators.html \\ + +http://www.math.ubc.ca/~cass/courses/m308-7b/ch5.pdf + +http://en.wikibooks.org/wiki/PostScript_FAQ + +: http://www.nihilogic.dk/labs/canvas_sheet/HTML5_Canvas_Cheat_Sheet.png + +http://dev.opera.com/articles/view/creating-pseudo-3d-games-with-html-5-can-1/ + +http://dev.opera.com/articles/view/html-5-canvas-the-basics/ + +js closure over value, not var! + +http://www.pvv.ntnu.no/~andersr/fractal/PostScript.html +http://www.cs.unh.edu/~charpov/Programming/L-systems/ +http://www.cs.unh.edu/~charpov/Programming/PostScript-primes/ + +http://www.adobe.com/print/features/psvspdf/index.html + + A PDF file is actually a PostScript file which has already been + interpreted by a RIP and made into clearly defined objects. + +http://c2.com/cgi/wiki?PortableDocumentFormat + + Unfortunately, Adobe have a history of making needlessly + incompatible changes to the PDF format. It's not quite as bad as + PostScript in terms of the number of broken documents out there, + but it's definitely not a stable format. + +hate pdf http://www.useit.com/alertbox/20030714.html + +* Ideas + +do better than http://processingjs.org/ http://processingjs.org/reference + +try 3d interface in chrome + +reactive programming http://conal.net/fran/tutorial.htm