wps

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

commit 7d089e5f79273c3644c826f5f6b9682490a08146
parent c6922a66864e796df87518b4a186f310e84bbaa3
Author: tomas <tomas@logand.com>
Date:   Sat, 23 Jan 2010 15:09:13 +0100

index.org from 2009-07-05

Diffstat:
Mindex.org | 1213++++++++++++++++++++++++++++++++++++-------------------------------------------
1 file changed, 546 insertions(+), 667 deletions(-)

diff --git a/index.org b/index.org @@ -1,39 +1,28 @@ -#+options: author:nil num:nil creator:nil timestamp:nil +#+title: WPS: PostScript for the Web +#+description: PostScript and PDF interpreter for HTML 5 canvas +#+keywords: PostScript, PDF, interpreter, HTML 5, canvas, JavaScript +#+options: num:nil toc:t +#+macro: ps [[http://www.capcode.de/help/$1][$1]] -PostScript and PDF interpreter in JavaScript +#+BEGIN_HTML: +<p class="h0">WPS: PostScript for the Web</p> +#+END_HTML -PostWeb \\ -WebScript +Welcome to WPS, a PostScript and PDF interpreter for HTML 5 canvas. -TODO reuse parsed wps.wps +Note that to see and run the examples, JavaScript must be enabled and +your browser must support HTML 5 canvas (latest Firefox, Opera and +Chrome should work). -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? +This document allows you to try simple PostScript programs in the WPS +sandbox. A few examples are presented here accompanied by a brief +description of the interpreter and listing some implementation notes +for my future reference. #+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 @@ -48,15 +37,98 @@ function $$(Id) {return $(Id).textContent;} </script> #+end_html +* WPS sandbox + +#+html: <canvas id="xsandbox"></canvas> +#+begin_html +<p>Sandbox:</p> +<p> +<textarea id="sandbox" style="width:100%" rows="18"> +/n 10 def +/w 25 def + +0 0 n w mul dup .gbox + +4 dict begin + 0 1 n 1 sub { + /i exch def + /ii 1 1 n div i mul sub def + 0 1 n 1 sub { + /j exch def + /jj 1 1 n div j mul sub def + ii jj 0 setrgbcolor + w j mul w i mul w w rectfill + } for + } for +end +</textarea> +</p> +<script> +function sandbox() {wps($("xsandbox"), [$$("wps"), $("sandbox").value]);} +</script> +<button onclick="javascript:sandbox();">Run</button> code from sandbox. +#+end_html + +* PostScript interpreter + +A few initial ideas and questions: + +- Learn and implement a Forth like language. PostScript seems like a + good 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 (and more). + - 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 code change, not for raw running speed. Keep + the code small and regular if possible. + - Can JavaScript be used as a portable assembler for the 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]]. +- It might be possible to implement different backend devices to be + used instead of HTML 5 canvas, for example a SVG device. +- Investigate the possibility of implementing a Lisp interpreter + suitable for production use in web applications. + +There are several things WPS is about: + +- stack(s) +- function (operator) dictionary +- reader +- interpreter/evaluator +- data types +- native bindings (JavaScript FFI) +- PostScript and PDF API + +[[http://en.wikipedia.org/wiki/PostScript][PostScript]] can be seen as a crossover between [[http://en.wikipedia.org/wiki/Forth_(programming_language)][Forth]] and [[http://en.wikipedia.org/wiki/LISP][Lisp]] +programming languages. It is (roughly) a programming language with +[[http://en.wikipedia.org/wiki/Reverse_Polish_notation][RPN]], complex data types, garbage collection and specialized +drawing operators. + ** Trivial example +The core essence of a RPN calculator is captured in the JavaScript +code bellow. + #+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 + = @@ -77,11 +149,20 @@ function ex1() { } </script> <button onclick="javascript:ex1()">Eval</button> -"<tt>1 2 = 3 + =</tt>" from harcoded stack +"<tt>1 2 = 3 + =</tt>" #+end_html +=Os= stands for Operand Stack, which holds arguments for operators. +=Sd= is a System Dictionary which contains definitions of operators +(JavaScript functions in this case). + ** Example with PostScript reader +PostScript has simple but non-trivial syntax so a reader which reads +text and creates internal PostScript objects is necessary. The reader +and evaluator is called =ps0= (an empty PostScript interpreter) in the +JavaScript code bellow. + #+html: <div id="example2"> #+begin_src js2 function example2(T) { @@ -104,177 +185,83 @@ function ex2() { } </script> <button onclick="javascript:ex2()">Eval</button> -"<tt id="ex2">12 34 + dup = 56 + =</tt>" from string +"<tt id="ex2">12 34 + dup = 56 + =</tt>" #+end_html +=Ds= is a Dictionary Stack allowing users to redefine existing +operators and revert back to the original ones. =Es= is an Execution +Stack which is used to implement a tail recursive evaluator. + ** Example with recursion +It is possible to write recursive code in PostScript. The following +PostScript code is from the [[http://www.math.ubc.ca/~cass/graphics/manual/pdf/ch9.pdf][Recursion in PostScript PDF document]]. + #+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 +/factorial1 { + 1 dict begin + /n exch def + n 0 eq {1}{n n 1 sub factorial1 mul} ifelse + end } def -%5 fib2 pstack clear +5 factorial1 = + +/factorial2 { + dup 0 eq {pop 1}{dup 1 sub factorial2 mul} ifelse +} def +5 factorial2 = #+end_src #+html: </div> #+begin_html <script> function ex3() {wps(null, [$$("wps"), $$("example3")]);} </script> -<button onclick="javascript:ex3();">Eval</button> +<button onclick="javascript:ex3();">Run</button> the example. #+end_html -* The interpreter +** Execution stack -A few initial ideas: +The interpreter manages its Execution Stack explicitly. -- 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. +Most operators simply: + +1. get their arguments from the Operand Stack +2. perform some computation and/or side effects +3. push results to the Operand Stack -Operators beginning with dot are non-standard low level operators -which are subject to change. +Some operators are more complex and involve some kind of control flow, +e.g. {{{ps(if)}}}, {{{ps(repeat)}}}, {{{ps(for)}}}, {{{ps(loop)}}} +operators. Such operators: + +1. get their arguments from the Operand Stack +2. perform single step of some computation and/or side effects +3. push the continuation (code and arguments to be executed next) to + the Execution Stack + +[[http://en.wikipedia.org/wiki/Tail_call][Tail Call Optimisation]] is implemented using [[http://logand.com/picoWiki/trampoline][trampoline]]. The evaluator +runs in a loop getting the next [[http://en.wikipedia.org/wiki/Continuation][continuation]] from the Execution Stack. +Operators that want to "continue" their execution (i.e. use the +interpreter to run other operators, including themselves) must perform +only one step at a time and save the remaining steps (continuation) on +the Execution Stack. + +For example, the {{{ps(if)}}} operator saves the "then" or "else" code +branch to the Execution Stack depending on the value of the "test" +argument. It does not "evaluate" the chosen branch directly +(recursively) but leaves the control to the evaluator loop. + +The whole process of interpreting is fed from JavaScript strings which +are obtained from the content of HTML elements (sometimes hidden from +this document). ** PostScript data types +PostScript has quite rich set of data types. +See [[http://www.adobe.com/devnet/postscript/pdfs/PLRM.pdf][PostScript Language Reference PDF document]] for more details. + | category | type | executable | example | spec | |-----------+-------------+------------+------------------------+--------------------| | simple | boolean | | true false | | @@ -295,7 +282,7 @@ which are subject to change. | | packedarray | | | Level 2 | | | string | Y | (hi) <a33f> | | -** Low level data types +The following data types are implemented in WPS: | category | type | direct | literal | executable | |-----------+------------+--------+---------+------------| @@ -310,7 +297,7 @@ which are subject to change. | | dictionary | Y | Y | - | | | string | Y | Y | - | -All types are represented directly in JavaScript except: +All the above types are represented directly in JavaScript except: | type | representation | |-----------------+-----------------| @@ -320,9 +307,15 @@ All types are represented directly in JavaScript except: | operator | function | | proc | quoted array | -*** exec +The interpreter needs to understand when to evaluate an argument. The +distinction between a "literal" and "executable" is the key. + +** Quoting and execution -pop any, case: +There are two important operators to control evaluation at the +PostScript language level. + +The {{{ps(exec)}}} operator usually leaves the argument as is except: | type | result | |-----------------+-------------------| @@ -330,9 +323,8 @@ pop any, case: | operator | apply operator | | proc | exec each element | -otherwise push the original value - -*** cvx +The {{{ps(cvx)}}} operator makes the argument "executable". Usually +leaves the argument as is except: | from | to | how | |--------------+-----------------+---------| @@ -340,13 +332,16 @@ otherwise push the original value | array | proc | quote | | string | proc | ~ parse | -** Stack - - +The ~ (tilde) character in the above table means that the +functionality has not been implemented yet. * Drawing with PostScript -Measuring angles: +As a convention, operators beginning with dot are non-standard, low +level operators which are subject to change. + +There is a difference in how HTML 5 canvas, PostScript and PDF measure +angles: | language/device | unit | |-----------------+------| @@ -354,8 +349,29 @@ Measuring angles: | PostScript | deg | | PDF | rad | +Many of the examples below set up their bounding box using the +=.gbox= operator, e.g. + +#+begin_src ps +0 0 180 180 .gbox +#+end_src + +Only the width and height of the canvas clipping rectangle are taken +into account so far. The width and height is related to the drawing +units rather than to the size of the canvas element. + +Both PostScript and PDF documents have the origin of the coordinate +system in the bottom left corner while HTML 5 canvas in the top left +corner. Thus, some of the following pictures are displayed upside +down unless an explicit coordinate transformation was added. This +discrepancy between the origin of the coordinate system is a problem +when drawing text because a simple coordinate transformation on its +own would draw the text upside-down. + ** Bowtie example +See the [[https://developer.mozilla.org/en/drawing_graphics_with_canvas#section_6][original example]] in JavaScript. + #+html: <canvas id="xbowtie"></canvas> #+html: <div id="bowtie"> #+include "bowtie.wps" src ps @@ -366,24 +382,14 @@ wps($("xbowtie"), [$$("wps"), $$("bowtie")]); </script> #+end_html -** Digital clock example - -#+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> +See the [[http://oreilly.com/openbook/cgi/ch06_02.html][original example]]. Click on the clock to start/stop it. +#+html: <canvas id="xclock2"></canvas> + #+html: <div id="clock2"> #+include "clock2.wps" src ps #+html: </div> @@ -393,100 +399,128 @@ wps($("xclock2"), [$$("wps"), $$("clock2")]); </script> #+end_html -** Tiger example - -Text drawing in canvas is not working in Firefox and Opera, works in -Chrome. +Running the clock keeps the CPU noticeably busy. Chrome is best with +very little overhead, followed by Opera, and Firefox significantly +worse than the previous two browsers. WPS seems to be fast enough for +one-off drawings, but its usability when running the interpreter in a +tight loop, depends on the efficiency of the host JavaScript +interpreter. -Firefox throws error about linecap and linejoin not being supported. -However, it does not throw error about missing support for text -drawing. - -#+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 | - -file:tiger.png - -** Fern example - -from http://www.pvv.ntnu.no/~andersr/fractal/PostScript.html +** Fill example -#+html: <canvas id="xfern"></canvas> +See the [[https://developer.mozilla.org/samples/canvas-tutorial/4_1_canvas_fillstyle.html][original example]] in JavaScript. -#+html: <div id="fern"> -#+include "fern.wps" src ps +#+html: <canvas id="xfill"></canvas> +#+html: <div id="fill"> +#+include "fill.wps" src ps #+html: </div> #+begin_html <script> -//wps($("xfern"), [$$("wps"), $$("fern")]); +wps($("xfill"), [$$("wps"), $$("fill")]); </script> #+end_html -** Tree example +** Tiger example -from http://www.pvv.ntnu.no/~andersr/fractal/PostScript.html +The [[http://svn.ghostscript.com/viewvc/trunk/gs/examples/tiger.eps?view=co][original example]] is included with [[http://ghostscript.com/][Ghostscript]]. -#+html: <canvas id="xtree2"></canvas> +#+begin_html +<canvas id="xtiger" style="width:283pt;height:369pt"> +</canvas> +<p>Drawing took <span id="msg">--</span> seconds.</p> +#+end_html -#+html: <div id="tree2"> -#+include "tree2.ps" src ps +#+html: <div id="tiger" style="display:none"> +#+html: <!-- TODO insert tiger.eps automatically --> #+html: </div> + #+begin_html +<div id="tiger1" style="display:none"> +0 0 567 739 .gbox +1 0 0 -1 0 739 .transform +/time1 .date (getTime) 0 .call def +</div> + +<div id="tiger2" style="display:none"> +/time2 .date (getTime) 0 .call def +(msg) .getElementById (textContent) time2 time1 sub 1000 div put +</div> + <script> -//wps($("xtree2"), [$$("wps"), $$("tree2")]); +function tiger() {wps($("xtiger"), [$$("wps"), $$("tiger1"), $$("tiger"), $$("tiger2")]);} </script> +<button onclick="javascript:tiger();">Draw</button> the tiger (be patient). #+end_html -** Other +Is this an interesting JavaScript and canvas benchmark? -1 0 0 0 setcmykcolor % 100% cyan \\ -0 0 1 0 setcmykcolor % 100% yellow +#+plot: title:"tiger.eps drawing times" ind:1 deps:(2 3 4) type:2d with:histograms set:"yrange [0:]" set:"xlabel 'browser'" set:"ylabel 'time [s]'" set:"style histogram gap 3" file:"tiger.png" set:"term png size 600, 300" +| browser | WPS time [s] | WPS time (no bind) [s] | PostCanvas time [s] | +|------------------+--------------+------------------------+---------------------| +| Chrome | 2.5 | 3.8 | 1.6 | +| Opera | 15.9 | 13.4 | | +| Firefox 3.0 | 15.4 | 19.5 | 7.4 | +| Firefox 3.5 | 11.6 | | | -** Fill example +[[http://www.feiri.de/pcan/][PostCanvas]] runs this [[http://www.feiri.de/pcan/example1.html][example]] about 1.5 times (Chrome) to 2 times +(Firefox) faster. I am actually surprised that WPS runs only up to 2 +times slower even though it interprets almost everything with minimal +number of operators coded directly in JavaScript (compared to +PostCanvas which implements all operators directly in JavaScript). -#+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 +Another surprise to me is that I expected more significant speed up +after implementing the {{{ps(bind)}}} operator. Why does Opera get +slower in this case? -** Chessboard example +It should be fairly easy to speed up WPS by adding more operators +implemented directly in JavaScript. This could be done dynamically by +redefining/rebinding existing operators to their optimized JavaScript +version. The speed of PostCanvas could probably be taken as the best +case that could be achieved by optimizing WPS though. -#+html: <canvas id="xchess"></canvas> -#+html: <div id="chess"> -#+include "chess.eps" src ps -#+html: </div> -#+begin_html -<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 +file:tiger.png + +Firefox throws error about linecap and linejoin not being supported so +these were not used here. Opera throws an error when running the +PostCanvas example. The tiger does not look the same as rendered by +[[http://projects.gnome.org/evince/][Evince]] ([[http://poppler.freedesktop.org/][poppler]]/[[http://cairographics.org/][cairo]]) so maybe the linecap and linejoin are +really needed to get proper image as intended. + +It is also interesting to observe that PDF operators and their names +probably came up from shortening/compressing "user-space" PostScript +operators in final PostScript files. The tiger.eps file was created +in 1990 and contains some "shortcuts" that match PDF operators +standardised later. * Drawing with PDF -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). +PDF is rather complex format. WPS implements only drawing operators +that can be present in PDF content streams. The number of these +operators is fixed and limited. Even though the full PostScript +language is not required, it can be convenient to implement them in +PostScript. + +However, some aspects (e.g. colors) are handled differently in PDF +compared to PostScript and these differences are not addressed by WPS. +I imagine that a supporting server-side solution like [[http://logand.com/sw/ondoc/index.html][OnDoc]] would +provide necessary data (e.g. decomposing PDF into pages and objects, +providing HTML 5 web fonts and font metrics) and WPS would only draw +preprocessed page content. + +Quoting from [[http://www.adobe.com/print/features/psvspdf/index.html][Adobe]]: + +#+begin_quote +A PDF file is actually a PostScript file which has already been +interpreted by a RIP and made into clearly defined objects. +#+end_quote ** Heart example +See also the [[https://developer.mozilla.org/samples/canvas-tutorial/2_6_canvas_beziercurveto.html][original example]] in JavaScript. + #+html: <canvas id="xheart"></canvas> #+html: <div id="heart"> -#+include "heart.wpdf" src ps +#+include "heart.wps" src ps #+html: </div> #+begin_html <script> @@ -498,7 +532,7 @@ wps($("xheart"), [$$("wps"), $$("heart")]); #+html: <canvas id="xrect"></canvas> #+html: <div id="rect"> -#+include "rect.wpdf" src ps +#+include "rect.wps" src ps #+html: </div> #+begin_html <script> @@ -508,9 +542,11 @@ wps($("xrect"), [$$("wps"), $$("rect")]); ** Triangles example +See also the [[https://developer.mozilla.org/samples/canvas-tutorial/2_3_canvas_lineto.html][original example]] in JavaScript. + #+html: <canvas id="xtriangles"></canvas> #+html: <div id="triangles"> -#+include "triangles.wpdf" src ps +#+include "triangles.wps" src ps #+html: </div> #+begin_html <script> @@ -520,9 +556,11 @@ wps($("xtriangles"), [$$("wps"), $$("triangles")]); ** Smile example +See also the [[http://developer.mozilla.org/samples/canvas-tutorial/2_2_canvas_moveto.html][original example]] in JavaScript. + #+html: <canvas id="xsmile"></canvas> #+html: <div id="smile"> -#+include "smile.wpdf" src ps +#+include "smile.wps" src ps #+html: </div> #+begin_html <script> @@ -532,9 +570,11 @@ wps($("xsmile"), [$$("wps"), $$("smile")]); ** Star example +See also the [[http://www.adobe.com/technology/pdfs/presentations/KingPDFTutorial.pdf][original PDF document]] where this example is presented. + #+html: <canvas id="xstar"></canvas> #+html: <div id="star"> -#+include "star.wpdf" src ps +#+include "star.wps" src ps #+html: </div> #+begin_html <script> @@ -542,325 +582,213 @@ wps($("xstar"), [$$("wps"), $$("star")]); </script> #+end_html -** Squares 2 example +** Squares example -#+html: <canvas id="xsquares2"></canvas> -#+html: <div id="squares2"> -#+include "squares2.wpdf" src ps +See also the [[https://developer.mozilla.org/samples/canvas-tutorial/5_1_canvas_savestate.html][original example]] in JavaScript. + +#+html: <canvas id="xsquares"></canvas> +#+html: <div id="squares"> +#+include "squares.wps" src ps #+html: </div> #+begin_html <script> -wps($("xsquares2"), [$$("wps"), $$("squares2")]); +wps($("xsquares"), [$$("wps"), $$("squares")]); </script> #+end_html -** Junk - -#+begin_html -<pre> - -1 0 0 -1 0 446 cm % 0,0 in bottom left corner - -% Ex4 - -q -%BT -%/F1 24 Tf -%1 0 0 1 260 600 Tm -%/CS1 cs -%63 127 127 sc -%(Hello World)Tj -%ET -%100 0 127 sc -%/CS2 CS -%0 0 1 SC -%315 572 m -%299 528 l -%339 554 l -%291 554 l -%331 528 l -%b -q -0 255 255 rg -4 0 0 4 315 550 cm -0 5.5 m --4 -5.5 l - 6 1 l --6 1 l - 4 -5.5 l -f -Q -%/CS1 cs -%63 127 127 sc -1 0 0 1 315 490 cm -0 0 m - -7 23 -40 19 -15 -17 c - -7.5 -27.8 -11 -22 0 -35 c - 11 -22 7.5 -27.8 15 -17 c - 40 19 7 23 0 0 c -b -Q - -% http://developer.mozilla.org/samples/canvas-tutorial/2_5_canvas_quadraticcurveto.html - -%75 25 m -%25 25 25 62 5 c2 -%25 100 50 100 c2 -%50 120 30 125 c2 -%60 120 65 100 c2 -%125 100 125 62.5 c2 -%125 25 75 25 c2 -%S - -%3 8 div 6 add . -%6 3 8 div add . - -%8 7 3 mul sub . -%7 3 mul 8 exch sub . - -/box { - 0 0 m - 72 0 l - 0 72 l - -72 0 l - h f -} def - -1 0 0 1 -452 124 cm -box -0 setgray fill -1 0 0 1 27.0 36.0 cm -box -.4 setgray fill -1 0 0 1 28.8 39.6 cm -box -.8 setgray fill - -% TODO not, and, or, xor -% TODO for loop exit -</pre> -#+end_html +** Two squares example -/MediaBox [0 0 612 446] +See also the [[https://developer.mozilla.org/en/drawing_graphics_with_canvas][original example]] in JavaScript. +#+html: <canvas id="xsquares2"></canvas> +#+html: <div id="squares2"> +#+include "squares2.wps" src ps +#+html: </div> #+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(); -// } -// }; -// 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"); -} +wps($("xsquares2"), [$$("wps"), $$("squares2")]); </script> #+end_html -#+html: <canvas id="c"></canvas> - -[[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> - -* JavaScript bindings - -http://www.whatwg.org/specs/web-apps/current-work/#the-canvas-element - -??? 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 -charpath setdash image putinterval dict begin settransfer -readhexstring flattenpath curveto pathbbox pathforall search transform -itransform definefont setrgbcolor setcharwidth - - setmatrix - -octal chars in string \234 +* Operators and JavaScript bindings +WPS implements a minimum core in JavaScript and the rest is +implemented in PostScript itself. -/Times-Roman findfont typography 15 scalefont setfont +Many JavaScript data types map quite easily to PostScript data types +so native bindings can be implemented mostly in PostScript via +PostScript dictionaries. [[http://www.whatwg.org/specs/web-apps/current-work/#the-canvas-element][HTML 5 canvas API]] bindings are quite +straightforward. Probably the trickiest bit is implementing callbacks +to handle [[http://en.wikipedia.org/wiki/Document_Object_Model][DOM]] events using PostScript code. ** 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 | +| category | in | operator | out | +|----------------+-------------------------+------------------+-------------------------------------------------------------| +| Trivial | | {{{ps(true)}}} | true | +| | | {{{ps(false)}}} | false | +| | | {{{ps(null)}}} | null | +| Math | x | {{{ps(neg)}}} | -x | +| | x y | {{{ps(add)}}} | x+y | +| | x y | {{{ps(mul)}}} | x*y | +| | x y | {{{ps(div)}}} | x/y | +| | x y | {{{ps(mod)}}} | x%y | +| Stack | | {{{ps(mark)}}} | mark | +| | x y | {{{ps(exch)}}} | y x | +| | | {{{ps(clear)}}} | | +| | x | {{{ps(pop)}}} | | +| | any_n ...any_0 n | {{{ps(index)}}} | any_n ... any_0 any_n | +| | any_(n-1) ... any_0 n j | {{{ps(roll)}}} | any_((j-1) mod n) ... any_0 ... any_(n-1) ... any_(j mod n) | +| | any_1 ... any_n n | {{{ps(copy)}}} | any_1 ... any_n any_1 ... any_n | +| Array | array | {{{ps(length)}}} | n | +| Conditionals | x y | {{{ps(eq)}}} | bool | +| | x y | {{{ps(lt)}}} | bool | +| | y | {{{ps(not)}}} | bool | +| | x y | {{{ps(and)}}} | z | +| | x y | {{{ps(or)}}} | z | +| | bool then else | {{{ps(ifelse)}}} | | +| | n proc | {{{ps(repeat)}}} | | +| | i j k proc | {{{ps(for)}}} | | +| Debugging | x | {{{ps(=)}}} | | +| | | {{{ps(pstack)}}} | | +| Dictionaries | n | {{{ps(dict)}}} | dict | +| | dict key | {{{ps(get)}}} | any | +| | dict key any | {{{ps(put)}}} | | +| | sym proc | {{{ps(def)}}} | | +| Arrays | n | {{{ps(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 | + +Some of the above operators could be implemented in PostScript instead +of directly in JavaScript. ** 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 +| category | in | operator | out | +|--------------+-------------+-----------------------+--------| +| Math | | {{{ps(abs)}}} | | +| | | .acos | | +| | | .asin | | +| | | {{{ps(atan)}}} | | +| | | .atan2 | | +| | | {{{ps(ceiling)}}} | | +| | | {{{ps(cos)}}} | | +| | | .exp | | +| | | {{{ps(floor)}}} | | +| | | {{{ps(log)}}} | | +| | | .max | | +| | | .min | | +| | | .pow | | +| | | .random | | +| | | {{{ps(rand)}}} | | +| | | {{{ps(round)}}} | | +| | | {{{ps(sin)}}} | | +| | | {{{ps(sqrt)}}} | | +| | | .tan | | +| | | {{{ps(truncate)}}} | | +| | | .e | | +| | | .ln2 | | +| | | .ln10 | | +| | | .log2e | | +| | | .log10e | | +| | | .pi | | +| | | .sqrt1_2 | | +| | | .sqrt2 | | +| | | {{{ps(sub)}}} | | +| | | {{{ps(idiv)}}} | | +| Stack | x | {{{ps(dup)}}} | x x | +| Conditionals | x y | {{{ps(ne)}}} | bool | +| | x y | {{{ps(ge)}}} | bool | +| | x y | {{{ps(le)}}} | bool | +| | x y | {{{ps(gt)}}} | bool | +| | bool proc | {{{ps(if)}}} | | +| HTML 5 | key | .gget | | +| | any key | .gput | | +| | key nargs | .gcall0 | | +| | key nargs | .gcall1 | | +| | | .gcanvas | canvas | +| | w h | .gdim | | +| | x0 y0 x1 y1 | .gbox | | + +** HTML 5 canvas methods and attributes + +*** Canvas methods + +| | in | canvas | out | ps | pdf | +|---+----------------------------------------------+-----------------------+----------------+--------------------------------+-------------| +| / | | | | < | < | +| | | .save | | {{{ps(gsave)}}} | q | +| | | .restore | | {{{ps(grestore)}}} | Q | +| | x y | .scale | | {{{ps(scale)}}} | - | +| | angle | .rotate | | {{{ps(rotate)}}} | - | +| | x y | .translate | | {{{ps(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 | | {{{ps(rectclip)}}} | | +| | x y w h | .fillRect | | {{{ps(rectfill)}}} | | +| | x y w h | .strokeRect | | {{{ps(rectstroke)}}} | | +| | | .beginPath | | {{{ps(newpath)}}} | m ? | +| | | .closePath | | {{{ps(closepath)}}} | ~ h ? ~ n ? | +| | x y | .moveTo | | {{{ps(moveto)}}} | m ? | +| | x y | .lineTo | | {{{ps(lineto)}}} | l | +| | cpx cpy x y | .quadraticCurveTo | | | | +| | cp1x cp1y cp2x cp2y x y | .bezierCurveTo | | | c | +| | x1 y1 x2 y2 radius | .arcTo | | {{{ps(arcto)}}} | | +| | x y w h | .rect | | - | ~ re | +| | x y radius startAngle endAngle anticlockwise | .arc | | ~ {{{ps(arc)}}} {{{ps(arcn)}}} | | +| | | .fill | | {{{ps(fill)}}} | ~ f ? | +| | | .stroke | | {{{ps(stroke)}}} | S | +| | | .clip | | {{{ps(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) | ~ {{{ps(setdash)}}} ? | ~ d ? | +| | any | .fillStyle | (black) | | | +| | num | .lineWidth | (1) | {{{ps(setlinewidth)}}} | w | +| | str | .lineCap | (butt) round square | ~ {{{ps(setlinecap)}}} | J | +| | str | .lineJoin | round bevel (miter) | ~ {{{ps(setlinejoin)}}} | j | +| | num | .miterLimit | (10) | {{{ps(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 + +| | in | canvas | out | ps | pdf | +|---+-----------------------------+---------------+-----+----+-----| +| / | | < | | | | +| | canvasGradient offset color | .addColorStop | | | | + +*** Other attributes | | dict | type | attribute | values | ps | pdf | |---+------------------+------------------+-----------+--------+----+-----| @@ -871,15 +799,21 @@ octal chars in string \234 | | imageData | canvasPixelArray | data | | | | | | canvasPixelArray | cnt | length | | | | -[IndexGetter, IndexSetter] CanvasPixelArray +TODO [IndexGetter, IndexSetter] CanvasPixelArray ** PostScript operators -| | category | in | operator | out | -|---+----------+---------+------------+-----| -| / | | < | < | < | -| | | x y [m] | transform | x y | -| | | x y [m] | itransform | x y | +| | category | in | operator | out | +|---+----------+---------+-----------------------+-----| +| / | | < | < | < | +| | | x y [m] | {{{ps(transform)}}} | x y | +| | | x y [m] | {{{ps(itransform)}}} | x y | +| | | gray | {{{ps(setgray)}}} | | +| | | r g b | {{{ps(setrgbcolor)}}} | | +| | | ??? | {{{ps(setfont)}}} ? | | +| | | | {{{ps(clippath)}}} ? | | +| | | text | {{{ps(show)}}} ? | | +| | | x y | {{{ps(rlineto)}}} | | ** PDF operators @@ -891,33 +825,33 @@ octal chars in string \234 | | | j | ~ setlinejoin | | | | M | setmiterlimit | | | | d | ~ setdash ? | -| | | ri | {SetColorRenderingIntent} | -| | | i | {1 .min setflat} | -| | | gs | {SetExtGState} | +| | | ri | | +| | | i | ~ {1 .min setflat} | +| | | gs | | | | Special graphics state | q | gsave | | | | Q | grestore | -| | | cm | .transform { //TempMatrix astore concat } | +| | | cm | .transform | | | 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 } | +| | | 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} | +| | | 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} | +| | | W* | eoclip | | | Text objects | BT | | -| | | ET | {grestore} | +| | | ET | ~ grestore | | | Text state | Tc | | | | | Tw | | | | | Tz | | @@ -933,8 +867,8 @@ octal chars in string \234 | | | TJ | | | | | ' | | | | | " | | -| | Type 3 fonts | d0 | setcharwidth | -| | | d1 | setcachedevice | +| | Type 3 fonts | d0 | setcharwidth | +| | | d1 | setcachedevice | | | Color | CS | | | | | cs | | | | | SC | | @@ -946,7 +880,7 @@ octal chars in string \234 | | | RG | rg | | | | rg | setrgbcolor | | | | K | k | -| | | k | setcmykcolor | +| | | k | setcmykcolor | | | Shading patterns | sh | | | | Inline images | BI | | | | | ID | | @@ -960,94 +894,39 @@ octal chars in string \234 | | 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 +* Supported Browsers -http://dev.opera.com/articles/view/creating-pseudo-3d-games-with-html-5-can-1/ +I have tried the following browsers so far: -http://dev.opera.com/articles/view/html-5-canvas-the-basics/ +| | Browser | Version | Note | +|---+---------+------------+------------------------------------| +| / | | < | | +| | Firefox | 3.0.11 | no text drawing, linecap, linejoin | +| | Firefox | 3.5b4pre | no text drawing, linecap, linejoin | +| | Opera | 10.00 Beta | no text drawing, ugly aliasing | +| | Chrome | 3.0.189.0 | arc drawing looks partially broken | -js closure over value, not var! +If you are using a different browser, please [[http://logand.com/contact.html][let me know]] if it works +for you. -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/ +* Limitations and Known Issues -http://www.adobe.com/print/features/psvspdf/index.html +- many PostScript operators are still to be implemented +- only small fraction of PDF operators has been implemented +- text drawing and font related functionality has not been implemented - A PDF file is actually a PostScript file which has already been - interpreted by a RIP and made into clearly defined objects. +* Changes -http://c2.com/cgi/wiki?PortableDocumentFormat +2009-06-30 v0.1 - 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. +- Initial version -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 - - -* LINKS - -http://www.math.ubc.ca/~cass/graphics/manual/ - -http://www.anastigmatix.net/postscript/MetaPre.html - -http://svn.ghostscript.com/ghostscript/branches/icc_work/psi/estack.h - -https://dev.mobileread.com/trac/iliados/browser/upstream/poppler/test/pdf-operators.c - -http://developer.apple.com/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_paths/dq_paths.html#//apple_ref/doc/uid/TP30001066-CH211-DontLinkElementID_10 +* References -http://easyweb.easynet.co.uk/~mrmeanie/matrix/matrices.htm +[[http://www.feiri.de/pcan/][PostCanvas]] is a RPN interpreter with many PostScript operators +implemented directly in JavaScript. It is faster than WPS but not a +"real" PostScript. -https://developer.mozilla.org/samples/canvas-tutorial/6_2_canvas_clipping.html +[[http://svgkit.sourceforge.net/][SVGKit]] has a PostScript interpreter on the wish list. -https://developer.mozilla.org/samples/canvas-tutorial/5_2_canvas_translate.html +Postscript is a registered trademark of [[http://www.adobe.com][Adobe Systems Incorporated]].