Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
postscript [2020/02/20 14:22] christian [exception handling example] |
postscript [2020/02/23 15:53] (current) christian [Get the code] |
||
---|---|---|---|
Line 9: | Line 9: | ||
===== Get the code ===== | ===== Get the code ===== | ||
- | Load the package | + | Load the packages **[Values]** and **[PostScript]** from the [[storeaccess|Cincom Public Store]] into your [[http:// |
- | Tests are in package **[PostScript Testing]**. | + | Tests are in package **[PostScript Testing]**. The package can be used stand-alone without PDFtalk. It only depends on the **[Values]** package. |
- | The bundle | + | The package is now part of the **{PDFtalk}** |
===== Use it ===== | ===== Use it ===== | ||
Line 46: | Line 46: | ||
Ultimately I want to extract text from PDFs for which I need CMaps. | Ultimately I want to extract text from PDFs for which I need CMaps. | ||
- | Also, I like PostScript. I used it quite a bit to write UIs with Display PostScript on a Sun Solaris | + | Also, I like PostScript. I used it quite a bit to write UIs with Display PostScript on a Sun NeWS(([[https:// |
===== PostScript programming introduction ===== | ===== PostScript programming introduction ===== | ||
Line 75: | Line 75: | ||
</ | </ | ||
leaves 49 on the stack. | leaves 49 on the stack. | ||
- | |||
At the start of a PostScript interpreter, | At the start of a PostScript interpreter, | ||
Line 81: | Line 80: | ||
* **global dict** " | * **global dict** " | ||
* **system dict** " | * **system dict** " | ||
+ | |||
+ | New definitions are put into the topmost dictionary of the stack. This allows programs to override system definitions. The NeWS system from Sun used this to implement an object oriented Display PostScript with the dictionaries as classes. Another view is to see the dictionaries as namespaces. | ||
+ | |||
+ | The dictionaries can be named with an interesting trick: the dictionary itself is stored under a key which is interpreted as its name. The system dict for example is constructed like: | ||
+ | <code smalltalk> | ||
+ | | dict | | ||
+ | dict := PSDictionary new. | ||
+ | dict at: #systemdict put: dict. | ||
+ | ^dict | ||
+ | </ | ||
+ | |||
+ | This creates a recursive structure which is not handled well by the standard Smalltalk dictionary, hence '' | ||
+ | |||
+ | Interestingly, | ||
+ | Including the naming scheme for dictionaries! | ||
(more will be written on demand...) | (more will be written on demand...) | ||
Line 90: | Line 104: | ||
There is a distinction about local and global VM, which, in my view, is an optimization not important for the language. Therefore, I did not implement this distiction (and hope that it really does not have any importance...). | There is a distinction about local and global VM, which, in my view, is an optimization not important for the language. Therefore, I did not implement this distiction (and hope that it really does not have any importance...). | ||
- | ==== exception | + | ==== Exception |
+ | When looking at CMaps in the wild, I encountered one where the PostScript was wrong. Instead of | ||
+ | <code postscript> | ||
+ | /CIDInit /ProcSet findresource begin 12 dict begin begincmap | ||
+ | </ | ||
+ | the program started with | ||
+ | <code postscript> | ||
+ | /CIDInit /ProcSet find begin 12 dict begin begincmap | ||
+ | </ | ||
+ | Instead of '' | ||
+ | |||
+ | To fix this I tried two approaches: the PostScript and the Smalltalk way. | ||
+ | |||
+ | In PostScript, you can just define the missing '' | ||
<code smalltalk> | <code smalltalk> | ||
+ | | source ps resources | | ||
+ | source := self exampleWrongSource. | ||
+ | ps := Interpreter new. | ||
+ | resources := [(ps run: source) resources] on: KeyNotFoundError do: [:ex | | ||
+ | (ex selector = #valueAt: and: [ | ||
+ | ex parameter = #find]) | ||
+ | ifTrue: [ | ||
+ | | ps1 | | ||
+ | ps1 := Interpreter run: '/find / | ||
+ | ex return: (ps1 run: source) resources] | ||
+ | ifFalse: [ | ||
+ | ex pass]]. | ||
+ | ^self newWith: ((resources at: #CMap) at: #F1) | ||
</ | </ | ||
+ | |||
+ | In Smalltalk you could just call the correct operator and resume: | ||
<code smalltalk> | <code smalltalk> | ||
+ | | source ps resources | | ||
+ | source := self exampleWrongSource. | ||
+ | ps := Interpreter new. | ||
+ | resources := [(ps run: source) resources] on: KeyNotFoundError do: [:ex | | ||
+ | (ex selector = #valueAt: and: [ | ||
+ | ex parameter = #find]) | ||
+ | ifTrue: [ex resume: (ex receiver valueAt: # | ||
+ | ifFalse: [ex pass]]. | ||
+ | ^self newWith: ((resources at: #CMap) at: #F1) | ||
</ | </ | ||
+ | I think that both approaches are very elegant. | ||