I usually look at ghostscript
as a command line tool; however, I never cease to be amazed at the sheer amount of settings and options present there - which is due to the fact that ghostscript
is a full blown PostScript language interpreter (which I often forget).
For instance, in Querying Ghostscript for the default options/settings of an output device (such as 'pdfwrite' or 'tiffg4'); one learns how to retrieve default options for a given output device. However, what I'd like to know is - are these options related to so-called PostScript dictionaries?
Or, to put it in other words - what are PostScript dictionaries; and what facilities does ghostscript
have, to query (and possibly) modify this data?
If you want to obtain a list of other dictionaries which are contained in the
systemdict
anduserdict
dictionaries, just run:This will produce a sorted list of dictionary names which you could investigate for potentially 'interesting' names.
You'll find such names like
Fontmap
,localdict
,AdobeGlyphList
,userparams
,.eexec_param_dict
,.substitutefamilies
,EncodingDirectory
,colorspacedict
,.distillerparamkeys
,devicedict
,.symbol_list
, ...With each of these names you can look up more or less interesting info and tidbits about Ghostscript's internals by running f.e.:
As you can see, even the Fontmap used by Ghostscript is stored in a dictionary. An extract of my results here locally is this:
Note of Caution: The above is not actually the file format as you'll have to use when you want to manipulate the Fontmap file that Ghostscript should use (in general, or for a particular job). For that format, please read the comments in an example Fontmap file as shipped by Ghostscript. The above list is the fontmap representation as Ghostscript stores in its internal dictionary.
To put it in the most simple terms: In PostScript, a dictionary is a list of key (name) + value pairs. Dictionaries allow the PostScript interpreter to lookup if a key exists and fetch its value to use it in any procedure. The interpreter also can create keys, store or modify values and even create complete custom dictionaries (dictated by the PostScript code its processing). Keys usually are of type name (but they may be of any other type as well with the exception of null).
Two of these dictionaries must always be present, for any implementation of a PostScript interpreter:
systemdict
This one holds pre-defined PostScript operators (and the implementations to make them do what the PostScript specification expects them to).userdict
This one holds variables and procedures of a PostScript program (think of 'procedures' as being functions or subroutines which are constructed by the combination of language-defined operators and program-defined values and parameters).One word about names: names are what to other programming languages are uniq identifiers (and they are case-sensitive). These identifiers may be variables or procedure names. They may be made up of any combination of the 256 characters of ASCII (but they are no strings).
As you may be aware, PostScript is a stack-oriented language. It uses several stacks:
operand stack This stack holds every single operand and every result of intermediate operations (turning the last result temporarily into the top-most element of the operand stack).
dictionary stack As the name says: this stack holds only dictionaries. As such the stack defines the current context for any key/name lookup.
execution stack This one holds executable objects, i.e. mainly procedures and files which are currently being executed. If the interpreter interrupts the execution of a current object, it puts the interrupted object onto this stack. After an object was completely executed, it is removed from the stack and execution continues with the one that is top-most now.
graphics state stack This stack hosts the current context for the ejection of graphical elements: current line width setting, current font, current color or grayscale value, current path... Current graphic states may be saved (
gsave
) and restored (grestore
) later. The top-most graphics state is always the current graphics state.All these stacks are independent from each other. However, the operand, dictionary and graphics state stacks are under the control of the PostScript program (that is, may be manipulated by it). The execution stack is the sole property of the interpreter.
For each stack there are certain limitations (as for the number of elements which may be stored on it, etc.). PostScript knows operators which can manipulate stacks: put a new element on the stack, remove the top-most element (
pop
), duplicate the top-most element (dup
), shuffle the order of elements on the stack (roll
), swap the two top-moste elements (exch
), and quite some more (a good intro into PostScript programming is the 'Bluebook' from Adobe).As I already said, dictionaries have their own stack which holds all dictionaries a PostScript interpreter may use.
On that stack there may be a separate dictionary of fonts, or any number of dictionaries a PostScript program wants to create (using the
dict
keyword) and use privately, or some dictionaries that are specific to a certain PostScript interpreter, such as Ghostscript.The
systemdict
always is the bottom-most one; above this is theuserdict
. These two cannot be removed from the dictionary stack, wheres all the other ones can be subject to any stack manipulation operator (such aspop
which removes the topmost element from a stack).Whenever the interpreter is looking up a name, it searches the dictionaries for that name, starting with the top-most dictionary. Hence
userdict
is searched beforesystemdict
. As soon as the name is found (a key), the interpreter stops searching and uses that key (or rather, the value it holds). The consequence of this architecture is that the PostScript programmer may overwrite any PostScript operator that is pre-defined insystemdict
with his own variant.Also, some dictionaries can be for the PS program 'private' (no-access, such as font dictionaries) or 'read-only'.
Update -- More answers:
userdict
orsystemdict
?The other answers already covered the "What are dictionaries?" part of your question. Now let's turn to "How can Ghostscript access them?"
Maybe the question should rather be: "How can I (a power user, a developer, a geek...) access them?"
You can print out the contents of any accessible dictionary that's known to your PostScript interpreter (which may be Ghostscript) by writing a simple PostScript program one-liner -- or by simply calling the interpreter (Ghostscript) with the program code handed over on the commandline (
-c ...
).You only need to know the name of the respective dictionary for this.
Let's look at one interesting such internal Ghostscript dictionary, called
.distillersettings
:Result:
This may not tell you much at the first glance. But you may recognize some of the key names in that dictionary:
/prepress
,/printer
,/screen
,/ebook
...All of these you can use on a Ghostscript commandline to ask for a pre-defined set of settings when you want output made by
-sDEVICE=pdfwrite
(the Ghostscript 'Distiller'-alike functionality). To ask for such a set of settings, simply add-dPDFSETTINGS=/printer
to the commandline.At the second glance now you'll see that the content of the
.distillersettings
dictionary essentially is a set of 6 more dictionaries. It is a 'dictionary of dictionaries'.Dictionary contents are not printed out by default (not with the PostScript code above). But if you want them, you can use a Ghostscript-specific procedure called
===
instead of the standard PostScript language operator==
in the above command. This procedure behaves the same as==
execpt that it also expands the dictionaries and prints all key:value pairs contained in them.Be carefull with that
===
procedure: the-dict-
you're trying to expand may be veeeeeery long and could cause you to loose your eyesight. :-)In our current case however it is still manageable:
Output now is:
Still not so nice. So let's try to get it better. The way we can do it is to modify our PostScript code: we tell it now to access the
.distillersettings
dictionary and get the value of one of the keys from it (let's use/screen
). Since we know that the value is another dictionary, we know we'll get another set of key:value pairs which we will be able to format the same way we did before:Now this looks nicer, doesn't it? See yourself:
As your sharp eye may have spotted already: some of the key values are again dictionaries. You are free to use the above command again, this time with a
===
in place of the second==
to resolve the mysteries that/GrayACSImageDict -dict-
and the like may keep hiding...In any case, now you know what you save on typing by simply using
-dPDFSETTINGS=/screen
instead of enumerating all the single parameters embedded in this/screen
dictionary...And you also know what single value you need to override should you want the general 'screen' quality output, but with the difference that all fonts get embedded:
You can explore a lot of interesting things this way about Ghostscript internals, if only you know the name of the dictionaries it uses. :-)
Dictionaires in PostScript are a 'container' object, they are in essence a list of pairs, a key and a value. See the PostScript Language Reference Manual for more details, especially section 3.3.9 in the third edition.
Dictionaries are often used to pass a set of parameters to a PostScript operator or function, for example the image operator can take a dictionary argument but they can equally well simply be storage.
Dictionaries can have access permissions, so it is possible to have read-only dictionaries, whose values can be examined, but not modified, and font dictionaries can be 'no access' to prevent the outline data being extracted in PostScript.
entries in a dictionary which is not read-only or no-access may be modified at will.
Lots of good answers already, but nobody's mentioned this:
When invoking ghostscript, the
-d
and-s
options create initial definitions in systemdict. This allows you to do parameterized invocation of your postscript program.Use
-dname[=token]
to set the value to null, or a number (or any other single postscript token). Use-sname=string
to set a string value (which in most contexts works as well as a name).And you can manipulate all the stacks to some extent with the right operators.
token
push to operand stack from string or file (this is what the interpreter loop uses to consume the program stream, so this is what you're using whether inputting code through a file or straight from the keyboard)pop
discard from operand stackbegin
push to dict stackend
pop from dict stackrun
,exec
,%procedure-invocation
push to exec stackexit
,stop
pop or clear exec stackgsave
push gstate on graphics stackgrestore
pop graphics stacksave
push a copy of all VM-contents (all dicts and arrays, but not strings)restore
rewind memory to saved state (revert all dicts and arrays to previous state)Dictionaries, being composite objects, inherit a number of operators common to all composite objects.
-typename-
create object, egdict
length
report size of objectput
insert an elementget
retrieve an elementcopy
populate an object with contents from another objectforall
do something to each element*load
alternate retrieve element (for dictionaries,load
performs a search withwhere
and then aget
; for arrays,aload
spills the entire contents of the array on the operand stack)*store
alternate insert element (for dictionaries,store
performs a search withwhere
and then aput
if found, ordef
if not; for arrays,astore
fills the array from objects on the stack)To this suite, dictionaries add
def
put into current dictionary (top of dict stack)known
query dictionary for an elementwhere
query all dictionaries for elementmaxlength
no longer interesting after PS Level 2 added auto-expanding dictionaries and gcdictstack
copy the dictstack into an array (maybe you wanna search bottom-up, you can!)names not preceded by a slash
/
are automaticallyload
ed and, if executable, executed//
whiletoken
is constructing a postscript object any names preceded by a double-slash areload
ed and substituted into the procedure array. This is very powerful, as you can mimic Lisp macros.Edit: One more thing. When creating a dictionary there is a time/space trade-off when you choose the size for the dictionary. Dictionaries are almost certainly implemented as a hash-table (in all but the simplest interpreters), and most hash-functions can avoid collisions when the table is about half-full (Rule of Thumb: Use double-sized dicts for speed). Since level-2, of course, dictionaries will grow automatically when you add size+1 elements, presumably by allocating a new dictionary of k*size (where k is probably 1.5 or 2); but controlling sizes manually can give you a speed boost. In level-1, if you're not multiply-referencing your dictionaries, you can install a replacement for
dictfull
inerrordict
to grow the dict and re-execute the put (or def or whatever). Since level-2 does this internally, it can replace all references.