Jaws specific features
4
Jaws specific features
Introduction
This section describes those language features in Jaws which are either not present in the standard PostScript language or documented as being product dependent. Most of these features are controlled by a number of extra PostScript language user parameters; some of them involve extra operators. The number of extra operators has been kept small to avoid conflict with application-generated PostScript language code.
Color overprinting
For an introduction to overprinting, you may find it useful to review Adobe Technical Note number 5044 Color Separation Conventions for PostScript Language Programs. This technical note, along with others, is available for free download from the Adobe Systems' web site www.adobe.com.
This technical note distinguishes between two different styles of creating separated color output.
The first is Level 2 "in-RIP" separations. In this case, color separation is performed by the interpreter itself when the Separations page device parameter is set to true. For some Level 2 devices, this parameter is permanently set to true, for some it is permanently set to false and some devices allow
PostScript language jobs to change its value to control generation of separated output.
In Jaws, the filepageseparation, filebandseparation, filebandcolour and anti aliased sample drivers, which are described in "Chapter 7", all allow a PostScript language job to set the Separations parameter to true. The second style is called (by Adobe) "host-based" separation, as it normally refers to stand-alone separation applications running on the host, producing "separated PostScript language file" output to be sent to the printer.
Actually, there is no such thing as "separated PostScript language files". When a user configures a page application or a stand-alone separation application to produce separated output, the result is a normal PostScript language file, containing four (or more) times as many pages, and with no colors in it except shades of gray.
There is no way for the interpreter to tell that the file it is processing originated as a composite color job. Unfortunately, the phrase "separated PostScript language code" or 'pre-separated" jobs has found its way into common usage. The PostScript language page descriptions in such a document are only related by their common origin: any overprint/knockout processing will have already been done when the document was created or separated.
Some applications use DSC comments to indicate plate color in such jobs, but there is no convention for what these comments should look like, and so there is no reliable way to detect "separated PostScript language" jobs, and no reliable way to detect individual plates within such jobs.
Normally, there is no conflict between "in-RIP separation" and "pre-separated" styles of output. Both take a PostScript language file representing a color document, and produce a series of monochrome pages of output, which may be printed with different colored inks and combined to produce printed color output. However, both styles of output use the setoverprint operator in different, and incompatible, ways.
For "in-RIP" separations, which work entirely within the PostScript language as defined in the PLRM, the setoverprint parameter only affects colors defined in a Separation color space. Overprinting only occurs if the colorant named in the color space's array is also present in the SeparationColorNames page device parameter. In this case, the tint transform procedure in the color space's array is not executed, and the color is rendered directly onto the correct plate of output. If the graphics state overprint parameter, controlled by setoverprint, is true, all other plates will be untouched by painting operations using this color space; if it is false, white will be painted on all other plates instead. If the named color is not being produced, the color space's tint transform procedure is executed, and the color is rendered in the nominated base color space; in this case the graphics state overprint parameter is ignored.
The PLRM states that although support for overprinting is required when generating separated color output in the RIP, it is also permitted when generating composite color output. Jaws supports overprinting with composite color output. All the comments in this section apply equally to CMYK separated output and 32-bit per pixel composite CMYK output. In addition, Jaws supports overprinting for RGB composite output, but only to the extent of consulting the graphics state overprint parameter when rendering a Separation color space whose name is Red, Green or Blue.
For "host-based" separations, setoverprint is treated as a pseudo-operator—in fact, it was used with Level 1 separation applications before it ever became part of the PostScript language in Level 2. The setoverprint operator is still regarded as controlling a notional graphics state overprint parameter. However, the interpretation of this parameter is now different, and it affects process colors specified with setcmykcolor as well as Separation color spaces. In this case, any of the process inks whose components are 0 are not painted if the overprint parameter is true, instead of being painted with white as they would be according to the PLRM.
Version 1.3 of PDF additionally supports the idea of "overprint mode", represented by the OPM parameter in the extended graphics state. This controls the interpretation placed on the value of the graphics state overprint parameter. A value of 0 corresponds to the "in-RIP" convention described above, and a value of 1 corresponds to the "host-based" convention.
Note: From version 3015 of Adobe's CPSI RIP onwards, it is possible to set the overprint mode using the setoverprintmode operator. Jaws also provides this feature.
The diagram below shows the effect of the overprint parameter in both styles, with a selection of different colors.
Figure 4.1 Overprinting rule 1
/CMYKOverprint | Boolean |
From Jaws v3003.0 this parameter is obsolete and deprecated.
This extra user parameter (that is, one not in the PLRM), is used to control overprinting behavior. This behaves just like any other user parameter, and is set by using the setuserparams operator, and may be examined by using the currentuserparams operator. The default value for this parameter is false. In this case, Jaws follows the "in-RIP" behavior for overprinting. If you set the CMYKOverprint parameter to true, Jaws will also follow the "host-based" convention for overprinting.
Note: overprintmode is equivalent to the CMYKOverprint user parameter. This parameter is now obsolete and should not be used. It is retained only for compatibility with earlier code.
This parameter is not part of the graphics state and should not be altered during the course of a page description. CMYKOverprint is intended to be used to set a "compatibility mode" for particular jobs, and not to obtain special graphics effects.
When CMYKOverprint is set to true, the extra "host-based" overprinting only affects output to CMYK. For composite output, this means a 32-bit per pixel CMYK raster.
For separated output, this means output generated with ProcessColorModel is set to DeviceCMYK, regardless of whether any additional output has been requested by setting SeparationColorNames. It is important to realize that the two conventions are not compatible, and therefore there is no universal setting which will produce "correct" output for all jobs. It is true that a job which uses the "host based" convention is unlikely to accidentally include PostScript language code which uses a Separation color space with the wrong value of the graphics state overprint parameter, as this would produce incorrect output on all PostScript language printers. However, because the graphics state overprint parameter does not normally affect DeviceCMYK colors, a PostScript language document using the "in-RIP" convention which attempts to minimize unnecessary code might leave the overprint parameter set to its last value while proceeding to render objects in the DeviceCMYK color space. If you attempted to render such a document with CMYKOverprint set to true, objects which were not supposed to overprint might show up as overprinting on the output from Jaws.
Normally, you would want to leave CMYKOverprint set to its default value of false. You should set it to true if you are going to be printing color jobs from non-Adobe authoring applications such as Freehand, which you know (or suspect) contains overprinted colors. Of course, not all colors in such jobs are overprinted, so it may not be necessary to change CMYKOverprint at all. You should never set CMYKOverprint when printing documents from Adobe authoring applications.
The symptom of leaving CMYKOverprint set to false when it should be true is that colors which should overprint will instead knock out. The symptom of setting it to true when it should be false is that some colors which should knock out will instead overprint.
In addition to CMYKOverprint, Jaws also supports two more extra user parameters to control different aspects of overprinting.
/CMYKPlaneMask | integer |
The first of these is CMYKPlaneMask. This allows Jaws to support an alternative method of specifying overprinting used by some applications, such as 3b2.
In this scheme, overprinting is specified by supplying a component value of -1 to setcmykcolor for those components which you wish to overprint. A component value of 0 indicates a knock-out, as usual. This is true regardless of the state of the graphics state overprint parameter. This method provides you with slightly more control, although it is much less widely used. When the CMYKPlaneMask user parameter is set to true, Jaws follows this convention for overprinting; when it is set to false, out of range operands for setcmykcolor are clamped to the range 0 – 1 as specified in the PLRM.
Figure 4.2 Overprinting rule 2
This convention for overprinting is the same as that adopted by the setcmykoverprint pseudo-operator described in Adobe Technical Note number 5044. That is to say, when CMYKPlaneMask is set to true, the setcmykcolor operator behaves identically to the setcmykoverprint pseudo-operator. However, as noted there, setcmykoverprint is the least used of all the methods of specifying overprint. Jaws implements setcmykoverprint as an operator, and its behavior is independent of CMYKPlaneMask.
As with the CMYKOverprint user parameter described above, CMYKPlaneMask only affects output to CMYK, whether Jaws is generating separated or composite output.
/BlackOverprint | Boolean/name |
Lastly, there is the BlackOverprint user parameter. This is different from the other user parameters relating to overprint, as it does not change the appearance of the job.
Instead, it controls whether pure black objects overprint or knockout on all other plates, independently of the setting of the graphics state overprint parameter, or any of the user parameters described above. Allowing black objects, and especially black text, to automatically overprint can reduce the effect of slight registration errors during printing.
The BlackOverprint parameter only affects the actual color black, and only process black, that is the color resulting from executing either:
0 setgray
or
0 0 0 setrgbcolor
or
0 0 0 1 setcmykcolor
Black colors arising from the use of Separation or DeviceN color spaces do not get automatically overprinted. Nor do very dark grays.
As with both CMYKOverprint and CMYKPlaneMask, BlackOverprint only affects output to CMYK.
The BlackOverprint parameter has three possible values. The default value is false, in which case no overprinting of black takes place, other than that requested by the PostScript language document itself. To enable automatic black overprinting for all objects, set BlackOverprint to true. To enable it for text only, set BlackOverprint to /TextOnly. In each case, specified objects which are printed in black, will overprint other plates instead of knocking out. As with the CMYKPlaneMask parameter, this operation takes place irrespective of the state of the graphics state overprint parameter.
Overprinting information is stored as part of the color specification in the graphics state, for use by OEM and kernel device class code. The current values of CMYKOverprint and CMYKPlaneMask are consulted as part of execution of the setcolor and so on, operators, and the color stored in the graphics state reflects any overprinting that results from their application. Any OEM-written code designed to perform color correction, for example, should take notice of the overprinting information, as changing the set of inks to be used for a particular graphic element which is designed to overprint can result in a major change to the appearance of the final output. The current value of BlackOverprint is consulted during rendering only, and does not affect the color information stored in the graphics state.
The behavior of overprinting may be affected by the value of the UseCIEColor page device parameter. When UseCIEColor is set to true, the setcmykoverprint operator behaves in the same way as setcmykcolor, and does not cause any overprinting.
The value of the UseCIEColor parameter does not explicitly affect the calculations controlled by the CMYKOverprint parameter. However, the color conversion step involved if, for example, the DefaultCMYK color spaces happened to be a CIEBased-DEFG color space, means that some non-zero components in the original color may be converted to zero values in the final device color, or some zero components may be converted to non-zero values. It is the component values for the final device color which are used to determine which inks mark the media and which do not, so the set of inks which mark the media for a given color may not be the same as those originally intended when the document was created. This may result in a visible change of color in areas on the page which were intended to overprint.
setcustomcolor and sethificolor
Closely related to Overprinting is the setcustomcolor pseudo-operator, also described in Adobe Technical Note 5044.
This is used in the Level 1 “host based” convention as a way of specifying spot colors in a composite color document. As such, it corresponds closely to the role filled by Separation color spaces in Level 2 PostScript language. Although it is not a real operator, and not part of the PostScript language, it has been adopted by many applications as the standard way of specifying spot colors.
Adobe provide a sample implementation of setcustomcolor and its companion operator customcolorimage as PostScript language procedures, and Jaws uses procedures based on these to implement these two pseudo-operators. The code for these can be found in the file %lib%utils.ps which is executed by
Jaws during initialization. There are one or two issues associated with the use of setcustomcolor which
may occasionally occur. The first is that a simple implementation of setcustomcolor does not hide the fact that it is based on the use of Separation color spaces. In particular, if the user has defined a custom color with the same name as one of the process inks, the tint transform function for the Separation color space will not get executed. If the specification of the color is different to the ink it apparently names, the “wrong” color will be rendered. This is not normally a problem for cyan, magenta, yellow or black, since most people are used to working with these inks. However, some problems may be caused if someone defines a custom color called Red which is not pure red. This is especially true, for example, when rendering a preview to the screen, in which case you will probably be rendering to RGB output instead of CMYK output. To deal with this situation, it is possible to change the behavior of the implementation of setcustomcolor used in Jaws so that it explicitly avoids defining a Separation color space whose name is the same as any of the standard process inks.
The topic of editing Jaws initialization files is covered in Chapter 6. The usual definition of setcustomcolor in %lib%utils.ps is as follows:
%% We use a special operator for the tint transform for custom
%% colours so that the kernel and the translator code can
%% recognise them
/setcustomcolorspace {
mark /Separation 2 index 4 get
%% To get the same behavour with unfortunate color names as
%% Adobe RIPs (which ignore p 198 of the PLRM), uncomment the
%% following lines. This changes names like (Black) to ( Black),
%% ensuring that the tint transform always gets executed. Note
%% however, that this may interfere with overprinting behavour.
% currentoverprint not {
% false [/Cyan/Magenta/Yellow/Black/Red/Green/Blue/gray] {
% 2 index eq {
% pop true exit
% } if
% } forall
% {
% dup length 1 add string
% dup 0 16#20 put
% dup 1 4 -1 roll putinterval
% } if
% } if
%%
/DeviceCMYK
mark 5 index aload pop pop
systemdict /stdtinttransform get ] cvx ] setcolorspace
pop
} binddef
/setcustomcolor { exch setcustomcolorspace setcolor } binddef
To change the behavior of setcustomcolor and customcolorimage so that they avoid separations with the same names as the standard inks, remove the commen characters (%) from the lines highlighted in bold above. The ink names are avoided by pre-pending a space to them, so that the kernel no longer recognizes them during Separation color space processing.
This behavior, although different from the sample implementation in Adobe Technical Note 5044, is the same as the implementation of setcustomcolor used by recent versions of Adobe applications. However, there is one side effect of this change.
Suppose that the user defines a custom color called “cyan” which really does represent the cyan ink. After changing setcustomcolor in this way, the kernel will no longer recognize it as cyan, and will always execute the color space’s tint transform procedure. In turn, this means that (assuming CMYKOverprint is set to false), this color new “cyan” will now never overprint, whereas the original color “cyan” would overprint according to the value of the graphics state overprint parameter.
A second issue with the setcustomcolor operator, and one which is harder to deal with, is applications which make incorrect assumptions about its implementation.
Most applications will emit some default definition of setcustomcolor in the PostScript language documents they produce. When the document is printed, it will first try to find a version of setcustomcolor defined in the printer, and if none is available, it will use its own default. For composite color documents, this is not a problem. However, difficulties can arise with preseparated documents.
The usual technique for generating separated PostScript language output is to redefine all of the basic color operators for each plate as described in Adobe Technical Note 5044, and then execute the same page description each time. Calls to setcmykcolor (or any other color operator) in the original page description execute the redefined setcmykcolor procedure, which calculates the correct tint for this plate and finally executes the setgray operator instead. An alternative technique might be to have an intermediate layer of “glue” procedures which your application uses to set color, and arrange for the glue procedures to execute setcmykcolor and so on for composite output, and setgray for separated output. Either approach will work so long as it is followed consistently, and either all color operators are redefined, or all glue procedures are redefined. The problem arises with documents produced by Corel applications, which use a glue layer, but which assume that setcustomcolor is a glue procedure, not an operator or pseudo-operator. This might still work, except that these documents only define setcustomcolor if it is not present in the printer—that is, they assume that any definition of setcustomcolor resident in the printer is the incompatible version used by Corel applications, and not the standard version defined by Adobe. The only way to render such documents correctly is to remove the definition of setcustomcolor from %lib%utils.ps.
A related issue, but one that is easier to deal with, is that some applications will correctly redefine setcustomcolor when generating separated output, but not customcolorimage (FrameMaker is one such application). The implementation for customcolorimage in %lib%utils.ps contains an implementation of customcolorimage which is usually able to detect whether it is being executed inside a preseparated document or a composite color document. Although it is less of a standard, Jaws also includes specimen implementations of the sethificolor and hificolorimage pseudo-operators in %lib%utils.ps. These implement the desired behavior in terms of DeviceN color spaces. Currently very few applications generate code which uses sethificolor and there are no known compatibility issues such as those described above for setcustomcolor.
Image handling
Jaws color space conversion is a series of named device classes, where it can be easily accessed and worked on.
Image handling
Jaws maintains a series of lookup tables—so-called "warp tables"—against each graphics state object that are used to rapidly convert colors from one color space to its base color space. When the color space in the graphics state is changed, the relevant tables are marked as "invalid".
When a request to render an image is encountered, Jaws must first ensure that the lookup tables required for the image's color space are valid, and to construct them if not. For most color space transformations, this will involve sampling the color space over the range of valid inputs, and storing the resulting samples in the warp table.
As each individual sample of the image arrives, the warp tables are applied to the sample color components. In some cases—such as in when converting a /Separation color space to its base space—there will be one input value that corresponds to one or more output values. In other cases, such as when converting CIEBasedABC, CIEBasedDEF, or CIEBasedDEFG color spaces, it is somewhat more complex because there are multiple input variables.
In addition, in the case of a construct like an /Indexed /Separation color space, Jaws combines the processing of the /Indexed and /Separation samples into a single lookup table and hence a single conversion step.
Once the samples have been converted to the final output colors space—this being defined by the color space itself or, in the base of CIE-based color spaces
Classes
Jaws Kernel Image Handling by the color rendering dictionary—they are passed down the device-class pipeline for processing by OEM code. This is shown in the following diagram.
Device classes are thus always presented with image data represented in one of the device-support colorants, and mapped such that a sample value of 0 maps to a color tint of 0.0, and that a sample value of 255 (or 1 in the case of a mask) maps to a color tint of 1.0.
The Jaws device class interface callbacks used by image handling are very straightforward. There is a group of three functions that are used; they are: dvclass_preimage(), dvclass_image(), and dvclass_postimage(). For each image that is processed, the preimage function is called once, then the image function is called repeatedly for each scan-line of the image samples, then the postimage function is called. This is illustrated in the following diagram:
h3.Device class image handling
Color space processing is a series of named device classes, operating independently of the kernel. With this method an OEM is able to replace the device classes with a custom conversion implementation. By disabling all of the conversions, OEM code is able to receive the entire range of PostScript language and PDF color spaces for sampled images as well as vector data.
Some of the processing must be carried out by the device classes themselves.
PostScript language file names
Jaws provides a mechanism for mapping PostScript language file names into host operating system file names. Of course, a portable page description should never use file names directly, although it may call for the loading of disk-based resources. However, your own initialization and other code may need to access disk files directly. Jaws allows you to access files in a number of different directories on the host, and provides a mechanism for converting PostScript language file names which may contain illegal characters such as ":" on Windows platforms, for example.
In Level 2 PostScript language, external files are stored on one or more "devices". For example, a simple file name such as foo.ps does not specify any device, but %lib%foo.ps specifies that the file is to be found on the %lib% device, whatever that is. There is no requirement that a PostScript language device correspond to a particular physical device, although it may do. In Jaws, each file device usually corresponds to one or more directories on the host file system. The ability to map a single device to more than one directory allows for a simple search path when sharing files between Jaws and other software running on the same machine.
The list of known devices is controlled by a table in the Jaws front-end code, described in "Jaws front-end interface"so it is under the control of the OEM.
As delivered, Jaws uses the following set of devices, which are always specified in the sample front-end code. If you remove any of these devices, you may have to make substantial changes to the PostScript language support files that ship with Jaws.
%lib% | is used for PostScript language "library" code. Mostly, this is code that is unconditionally read into the interpreter on startup. It is possible for this code to be customized and this is discussed in "Chapter 6". |
%resource% | is used for most PostScript language resource files, including procedure sets, color rendering dictionaries, standard encodings and so on. Normally, this is treated as read-only data, although you may want to add your own resources to certain categories—color rendering dictionaries for particular output devices, for example. CID fonts are normally also stored on this device in %resource%CIDFont. |
%font% | is used for all other PostScript language font files. Jaws ships with a standard set of 35 "clone" fonts in CFF format in this directory. If you want to install extra fonts, you can either install them in the standard Jaws font directory on the host file system, or add another directory to %font%, or store them somewhere else and modify the searching code in the font resource implementation dictionary. |
%temp% | is used as the default location for temporary files that may be created by Jaws, such as display list temporary files. Using the %temp% device allows your code to portably open temporary files without worrying about the details of the host operating system. In most cases this is merely a convention—you can, for example, change the location used for display list temporary files to any valid PostScript language file name. However, %temp% is used by the kernel for ReusableStreamDecode filters if it decides that the file should be stored on disk, so %temp% is one file device which must always be present. The OEM can override the default location for ReusableStreamDecode temporary data. See also %ram% . |
%default% | is an optional file device that is treated specially by Jaws. If it is present, all otherwise unqualified file names such as foo.ps will be treated as if they were actually %default%foo.ps. If it is not present, Jaws will search every file device in turn for the file. |
%ram% | is a special file system which may be used for storing small temporary files. This is used by the kernel for ReusableStreamDecode filters if it decides the file should be stored in memory. |
Some font installers assume that files are laid out on disk in the same way as on a Level 1 interpreter. They assume, for example, that there is a top-level directory called fonts in the PostScript language filing system.
Jaws allows the OEM to map old-style file names, such as
fonts/foo
into Level 2 file names, such as
%font%foo
This is done, via the "deviceremap" table. The default table is:
char *deviceremap = "encodings=%resource%Encoding, fonts=%font%,
charstrings=%resource%CharStrings, temp=%temp%";
The translated file name is then used internally for all file system operations. In addition, Jaws supports different file system implementations.
The file system table in Jaws allows you to associate different file systems with each of the file devices you specify.
The RAM file system is used to implement the memory-based files that reside on the %ram% device. There is a companion ROM file system which is normally only used on embedded systems, or when PostScript language resources need to be sheltered from the user. Contact Jaws Support for more details.
The host format file system passes all file operations straight through to the underlying host operating system. Use of this file system requires that all PostScript language file names are also legal file names according to the host operating system. Anomalies in the host file system, such as case insensitive names, or a separator character other than "/", will also appear in the PostScript language file device.
On Unix systems, all file devices use the host filing system, as the semantics of Unix file naming are the same as for the PostScript language. For some old versions of Unix that impose an unacceptable limit on the length of file names (such as CLIX), it is possible to use the emulated file system instead.
Specification of file devices is done in OEM front-end code, and is described in "Jaws front-end interface".
Some PostScript language file names are handled specially: A simple file name, such as:
(foo) | is interpreted in one of two ways. |
(%default%foo) | If no %default% device has been defined, Jaws will search each file device in turn for the file. |
(/data/tmp/foo) | which is also an absolute file name on Unix. Jaws always maps file names like this to: |
(%os%/data/tmp/foo) | The %os% device is always defined, and always uses the host file system. If you defined a specific directory for the %os% device, this directory will appear to be the root of the PostScript language filing system (at least as far as absolute path names are concerned). |
(Macintosh HD:foo) | will be recognized as an absolute file name by the Macintosh version of Jaws. |
The emulated file system is used to implement PostScript language semantics (long file names, case sensitive file names, characters such as ":" in file names) on systems where the host operating system does not support them. Typically this means the Macintosh and PC versions of Jaws.
The emulated file system implements a file system with case sensitive file names up to 1023 characters (which can include punctuation such as colons), and the path separator is a '/ʹ character. Where the emulated filesystem is used, the %lib%, %resource% and %font% devices use it to allow for portable naming of PostScript language resources, including fonts.
The Jaws emufs code emits PostScript language filenames as strings if they are longer than 127 characters. PostScript language filenames represented as strings do not have length limit.
Every directory in an emulated file system will contain a file called edir, which is used by the emulated file system code. Whenever Jaws creates or deletes a file in this directory, an updated edir file is written out to disk. This file lists the PostScript language file names in the directory, and the host file names that they should be mapped to. Both sub-directories and plain files are listed. The format of the file corresponds to PostScript language syntax. The file is an unsorted list of pairs of file names: the first in each pair is a PostScript language name or PostScript language string giving the PostScript language name of the file, and the second is a PostScript language string giving the actual name of the file on disk.
If any directory on an emulated file system does not contain edir Jaws will treat that directory as empty, and will write edir the first time that a file is created in the directory. Any files in a directory which are not explicitly listed in edir will not be visible to Jaws.
So, for example, the edir__ file for the %lib% directory on the PC and Macintosh versions of Jaws looks like this:
/errordict.ps(errord.ps)
/init.ps(init.ps)
/resources.ps(resource.ps)
/statusdict.ps(statusd.ps)
/utils.ps(utils.ps)
The edir files may be edited by hand, but you should exercise care when doing this. The PostScript language file name should be a valid PostScript language file name, the host file name should be valid for the platform you are on, and it should refer to a file that actually exists. You should use an editor that does not add spurious characters to the file— for example, many PC text editors will add a control-Z character to the end of a text file and are therefore not acceptable.
Note: The edir files for the top-level directories on each file device are read in during interpreter initialization; after that the edir files for subdirectories are read in the first time that the directory is referenced by PostScript language file operators. Although the files are written out to disk when PostScript language code creates or deletes a file in any given directory, they are usually only read in once. Once any edir file has been read in, any changes you make to edir files by hand while Jaws is running will not be acted on until the next time Jaws is started.
There is another kind of file system which allows you to "alias" one directory to another. For example, a number of font installers assume that the devices on a printer are called %disk0%, %disk1% and so on, and that there is a top-level directory fonts on each device. Although this goes against the recommendations in the PLRM concerning the use of ResourceFileName to obtain the file name to use when installing a resource, these downloaders do it this way in order to be able to search for a disk with enough free space to install the font. Jaws allows you to alias %disk0%fonts to the same host directory as %font% if you should need to run a font installer that works like this. The details of how to do this are covered in the description of the front-end file system table, see "Tables".
Rendering PDF files
Jaws supports the Portable Document Format defined by Adobe and used by Adobe Acrobat products. This format is described in the PDF Reference Manual, published by Adobe.
PDF files contain not just page descriptions, but also extra information including document structure, hypertext links, annotations, and article threads. With one exception, Jaws only reads the page description information from the file.
PDF files use the same fundamental graphics model as the PostScript language, and many PDF operators map straight onto PostScript language operators. In addition, a document stored as a PDF file features page independence. That is, each page from the file can be rendered independently of any other, and any subset of pages in the file can be rendered in an arbitrary order. Normally, this is not possible with documents stored as PostScript language files,
as each page in the file may depend on resources (fonts, for example) defined on preceding pages.
Page independence has one important consequence for any product which interprets or renders PDF files. The page descriptions and resources used by those page descriptions are all stored as separate, independent, objects within the file. This means that the PDF consumer must be able to seek to different positions within the file to read various objects into memory as they are needed. PDF is, therefore, a random access file format, and you cannot simply execute a PDF file from start to finish, as you can a PostScript language file. This in turn means that before Jaws can render it, a PDF file must be stored on a local disk. A PDF file cannot just be fed into %stdin in the way that a PostScript language document can.
Adobe Acrobat products are deliberately tolerant of PDF files that contain spurious data at either the start or the end of the file (for example, if the file was received via e-mail). Jaws expects that the file conforms to the format described in the PDF Reference Manual and should begin with the line:
%PDF-1.x
and end with the line
%%EOF
Jaws provides a group of extension operators for rendering PDF files.
string PDFfile file
The PDFfile operator takes a single operand, a string containing a valid PostScript language file name. It opens this file and reads in the trailer dictionary. From this, it constructs a special object representing the open PDF file. This is not a normal PostScript language file object, and it may only be used as an operand to the PDF rendering objects. The object representing the file is completely opaque, and the type operator will return a result of pdffiletype when applied to it. The underlying PDF file will be closed when the object is garbage collected, usually as a result of executing the restore operator.
As an example:
/mypdffile (relnotes.pdf) PDFfile def
opens the file %default%relnotes.pdf and stores the resulting PDF file objects as mypdffile.
From 2002.4 the operation of PDFfile has altered slightly; existing code will continue to work as before but to handle encrypted PDF files it is now necessary to supply a password to Jaws so that it can decrypt the file.
If you attempt to open an encrypted PDF file, PDFfile will signal an ioerror and place a message in errorinfo indicating that the file is encrypted. As noted above, an encrypted file is any file which contains an Encrypt entry in the trailer dictionary, or equivalently, one for which Acrobat Reader reports any security method other than "none". Not all encrypted files require a password to be viewed or printed by Acrobat.
file PDFpagecount int
The PDFpagecount operator counts the number of pages in the PDF file supplied as an operand on the stack. It returns the count of pages as an integer on the operand stack.
file pageno PDFpagebbox xlo ylo xhi yhi file pageno PDFpagecropbox xlo ylo xhi yhi file pageno PDFpageartbox xlo ylo xhi yhi file pageno PDFpagetrimbox xlo ylo xhi yhi
file pageno PDFpagebleedbox xlo ylo xhi yhi
All these operators return bounding box information for the given page in the given PDF file. The PDFpagebbox operator returns the value of the page's MediaBox, the other operators return the value of the corresponding box (for example, PDFpagecropbox returns the page's CropBox and so on), if present, or the MediaBox otherwise. If a page has a value of Rotate other than 0, the requested rotation is applied to the bounding box before returning the result. The centre of rotation is taken to be at the point (0, 0), which is usually at the bottom left-hand corner of the page in its original orientation.
The MediaBox is used by Acrobat products to determine the page size for printing; either the MediaBox or the CropBox may be used by them to display the page size for viewing. The other entries have meanings as described in the PDF specification.
Note: xlo, ylo and so on, are the x, y co-ordinates of the bottom left and top right corners of the various boxes.
file pageno PDFpage -
file dict PDFpage -
The PDFpage operator renders a single page from the PDF file, and optionally renders any annotations on that page. The operator takes one argument on the stack, either an integer or a dictionary:
In the first case, the PDFpage operator renders a single page from the PDF file. The file and page number are supplied as operands on the stack. This operator has no explicit result.
The PDFpagefields operator is now deprecated so to handle transparent annotations, code must be modified to use the PDFpage operator.
The PDFpage operator can render annotations as part of the page content, instead of as a post-rendering operation, thereby correctly rendering transparent areas.
When called with a single integer operand, the behavior is that PDFpage renders the page represented by the integer argument.
If it is instead supplied with a dictionary operand, PDFpage renders the page and the requested annotations. The dictionary operand must contain a /PageNumber key, the associated integer value replaces the integer operand, and is the number of the page to be rendered.
The dictionary may contain a /FDF key; if present this must be associated with an array, which controls the rendering of annotations. This array has the following form:
file pageno [array] PDFpage -
As an example, the following code will render a form, and then render the fields that comprise the form, lastly printing the whole using showpage:
mypdffile
<<
/PageNumber 1
/FDF [
<<
/T (Name)
/V (Fred Flintstone)
>>
<<
/T (Address)
/V (Bedrock)
>>
]
>>
PDFpage
Parsing comments
Jaws allows you to monitor comments in PostScript language code as it is being executed.
/CommentDict name
There is an extra user parameter, whose keys are names and whose values are PostScript language procedures. The names in this dictionary reflect the names of the comments you wish to monitor, and the procedures are code which is executed when each comment is encountered.
Because it is a user parameter, CommentDict is set by means of the setuserparams operator. Successive calls to setuserparams with a CommentDict entry will overwrite the value of CommentDict, the new contents are not merged with any existing contents. This means that if you are writing code which might combine two or more sets of comment procedures, you should take care to combine them into a single dictionary before passing that dictionary to setuserparams. Like any other user parameter, CommentDict is subject to save and restore and in particular it will be reset to its initial state during the global restore which occurs at the end of every job. Comment parsing only affects PostScript language program code being read from files. It does not affect the operation of the token operator, nor does it affect the exec or stopped
operators when they are applied to executable string objects. It also does not affect any of the file operators other than token, exec, run or stopped. In addition, if findresource causes any disk-based files to be executed, comment parsing is inhibited for those files.
Jaws allows you to monitor three categories of comments, intended to help you make use of DSC (document structuring convention) comments.
The first is the header comment %! which appears at the start of any DSC-conforming PostScript language or encapsulated PostScript language file. If your CommentDict dictionary contains a procedure whose name is Magic, that procedure will be executed each time Jaws encounters a comment line beginning with %!, in the manner described below. Remember, if a PostScript language document includes other, encapsulated PostScript language files, it may contain multiple such comments in addition to the one at the start of the file.
The second category is DSC comments, characterized by two percent characters followed immediately by a capitalized word. In this case the procedure in CommentDict should have the same name as the comment. For example, a procedure in CommentDict named BoundingBox will be executed whenever Jaws encounters the comment:
%%BoundingBox:
The third category is DSC vendor-specific comments, characterized by one percent character followed immediately by a vendor-specific alphabetic prefix followed immediately by a keyword. As for DSC comments, the procedure in CommentDict should have the same name as the comment. For example, a procedure whose name is ALDImageFileName will be executed whenever Jaws encounters the comment:
%ALDImageFileName:
In addition to this, Jaws allows an extra entry in CommentDict called CommentNotFound. If this entry is present, its procedure will be executed whenever Jaws encounters a DSC comment which does not have a matching entry in CommentDict. Jaws only applies CommentNotFound to DSC comments, not to header comments or DSC vendor-specific comments.
So, for example, you can dump out all of the DSC comments in a document by executing:
<<
/CommentDict <<
/CommentNotFound {==}
>>
>> setuserparams
before interpreting the document.
When the procedures are executed, the top of the operand stack holds a string which contains all of the comment line after the initial one or two percent characters. In particular, the string includes the comment name itself, so you can have multi-purpose procedures which are capable of handling more than one kind of comment. Your procedure can of course use the token, search or anchorsearch operators to split up the string. For example, if you were parsing a BoundingBox comment, you would probably want to start by executing:
(BoundingBox anchorsearch pop
to strip off the comment keyword and colon, leaving a string on the stack containing either the keyword (atend) or the four numbers for the bounding box.
Because the procedures in CommentDict are executed at a time when the PostScript language document does not expect any code to be executed, it is even more important than usual to ensure that the procedures do not have any side-effects on the operand or dictionary stacks other than to pop the string operand passed to the comment procedure when it was invoked.
When parsing a comment, Jaws looks for any continuation lines which may be present, and concatenates then all into one comment before calling your comment procedure. So, for example, if the original file contains:
%%DocumentCustomColors: (PANTONE 376 CVC)
%%+ (PANTONE Orange 021 CVC)
the string that will be passed to your DocumentCustomColors procedure is:
(DocumentCustomColors: (PANTONE 376 CVC) (PANTONE Orange 021 CVC))
As a more comprehensive example, the following shows how you might implement a simple set of dictionaries to enable Jaws to print both PostScript language document and EPS files. This example is designed to achieve three
things: first, to identify an EPS file; second, to extract the bounding box information from its header, as EPS files should not contain any calls to setpagedevice; and third, to check whether the file executes showpage, and if not, to automatically execute showpage at the end of the file.
This example deliberately ignores the issue of how to handle an EPS file which includes PICT, TIFF or Metafile preview information. Such files require you to strip binary data from the file, and are probably better handled in your application front-end than in the interpreter.
The code shown below is intended to be run just before the PostScript language document. It can either be prepended to the job itself, or run from inside the job server loop in %lib%init.ps.
First of all, the code needs some variables to record whether a showpage has been executed, whether the BoundingBox: comment has been encountered, and whether the document incorporates any included EPS files. Since these variables need to exist over the lifetime of the job, independent of any saves and restores there might be in the document, these variables are stored in globaldict. A more thorough implementation might create a special dictionary in globaldict for this purpose, but the risk of interference from other code is slight, so we can (for now) ignore that complexity.
globaldict begin
currentglobal true setglobal
/showpageseen false def
/boundingboxseen false def
/epsfdepth 0 def
We need to set VM allocation mode to global because we are about to define some dictionaries and procedures in globaldict too. The general strategy for the code is to have not one but three co-operating dictionaries.
The first dictionary, cd1 shown below, is used at the beginning of the document, and its job is solely to decide whether this is a PostScript language document or an EPS file. For DSC-conforming documents, this is easy, we just look for the string "EPSF" in the header comment. Just in case we encounter a document with no header comment, there is a fail-safe: if the document contains an EndComments comment before the first header comment, we can assume that it is a PostScript language document. This prevents PostScript
language documents that include EPS file (and their headers) being incorrectly treated as EPS files, even if their header comment is missing.
Of course, if a document does not conform to the DSC specification and has no header comment, it may well not have an EndComments comment either. In this case, you might want to hook some operator such as setpagedevice to make sure that if no comments have been recognized by the time setpagedevice is executed, you can assume you have a PostScript language document.
For information on hooking operators, see "Patching operator definitions" but we shall ignore this possibility for now and assume that we are given conforming documents.
/cd1 <<
/Magic {
(EPSF) search { pop pop pop
<</CommentDict globaldict /EPSFcd get >> setuserparams
<<
/EndPage [
{dup 0 eq {globaldict /showpageseen true put} if}
/exec load cvx currentpagedevice /EndPage get
/exec load cvx ] cvx
>> setpagedevice
} {
pop
<</CommentDict globaldict /PScd get >> setuserparams
} ifelse
}
/EndComments {
<</CommentDict globaldict /PScd get >> setuserparams
} >> def
If the file does turn out to have an EPS header comment, the code above resets the CommentDict user parameter to be the dictionary that handles EPS files, EPSFcd shown below, and also sets the EndPage procedure in the current page device so that it monitors whether or not the file executes showpage. This code prepends:
{dup 0 eq {globaldict /showpageseen true put} if}
to the existing EndPage procedure so as not to interfere with any other code. By the time Jaws reaches the end of the file, showpageseen will be true if showpage has been executed, and to false otherwise.
If the file turns out to have a PostScript language header comment, the code resets CommentDict to be the dictionary that handles PostScript language documents, PScd. In fact, this turns out to be an empty dictionary as no further comment processing is required in this case:
/PScd << >> def
It remains to define EPSFcd. This has to parse the file's BoundingBox: comment to extract the page size information and execute setpagedevice. The code that does this must only take action on the first such comment—if a file contains other included EPS files, they will each have a BoundingBox: comment, and we do not want to pick up the page size from those by mistake. We must also avoid calling setpagedevice as a result of a BoundingBox: appearing at the end of the file—this would just erase the entire page. We use the boundingboxseen flag to make sure we only do anything with the first BoundingBox: comment to avoid these problems.
The code for EPS files also needs to execute showpage if the file does not execute it for itself. To do this, we watch for EOF comments. If the showpageseen flag has not been set to true by the EndPage procedure by the time we get to the EOF comment, we just execute showpage to cause the output to be printed. As with BoundingBox: comments, if the file contains other included EPS files, we need to be careful that we catch the right EOF comment, except that in this case the last EOF comment is the one we want. To handle this, we keep a running count of the depth of nested files by counting BeginDocument and EndDocument comments, and only take action on the outermost EOF, when the depth has returned to zero.
/EPSFcd <<
/BeginDocument { pop
globaldict /epsfdepth 2 copy get 1 add put
}
/EndDocument { pop
globaldict /epsfdepth 2 copy get 1 sub put
}
/BoundingBox {
globaldict /boundingboxseen get not { globaldict /boundingboxseen true put (BoundingBox anchorsearch pop pop
(atend) search {
pop pop pop
} {
cvx exec
index 4 index sub 1 index 4 index sub
array astore << /PageSize 3 -1 roll >> setpagedevice pop pop neg exch neg exch translate
} ifelse
} if
}
/EOF {
pop
globaldict /epsfdepth get 0 eq {
globaldict /showpageseen get not {showpage} if
} if
} >> def
Lastly, we do some tidying up and install the first dictionary:
setglobal
end
<< /CommentDict globaldict /cd1 get >> setuserparams
This example shows a realistic, if rather simple, set of dictionaries for parsing comments in real jobs. In practice, you may find that the need to correctly handle files that do not conform to the DSC specification means that your comment dictionaries may become significantly more complex.
h2.OPI support
Jaws incorporates an extra decode filter type for reading images contained in TIFF files. This filter, along with two sets of comment dictionaries of the kind described in the previous section, allows some limited support for handling of OPI replacement images. This facility is not intended to replace a fully specified OPI server, however, depending on how well controlled your environment is, it can be used to eliminate the need to place the high resolution image back into the job prior to interpretation.
One example of a situation in which you cannot use Jaws without an OPI server is if you are trying to place color images in preseparated PostScript language files, or vice versa—quite obviously this cannot be done without some other external processing of the image. The discussion below assumes that you are working in a situation where it makes sense to use Jaws to substitute the images.
Like other filters, a TIFFDecode filter is opened by using the filter operator. When you open the filter, you must provide a parameter dictionary, and the underlying file for the filter must be a seekable (that is, disk-based) file. If either of these is not true, the filter operator will signal a rangecheck error. The filter operator examines the underlying file and reads a TIFF header from it. It then creates and returns the filter file object as its explicit result on the operand stack, just as it does for any other filter type. In addition to this, it fills in the following entries in the parameter dictionary which was supplied as an operand, from the information contained in the TIFF header:
Width | the width of the image, in samples. |
Height | the height of the image, in samples. |
BitsPerComponent | the number of bits per sample per color. |
Photometric | the photometric interpretation of the image. |
Palette | if the image has a color map, this field contains the color map read from the file. |
The first three of these may be used directly in a PostScript language image dictionary. The others can be used to construct Decode arrays and Indexed color spaces for the image. The TIFF filter file object can be used directly as the DataSource in a PostScript language image dictionary. Reading from the filter file returns the uncompressed samples from the image, in natural sample order, left to right, top to bottom. Color images will be returned as a stream of pixel-interleaved samples ("chunky" format in TIFF terminology) regardless of how the data is interleaved in the underlying disk file.
The TIFFDecode filter is designed to read TIFF baseline images, within the meaning of the TIFF 6.0 specifications, as well as LZW, CCITT and JPEG compressed TIFF images.
Although you can use the TIFFDecode filter from within your own PostScript language code, it is primarily intended for use with two procedure sets which are supplied with Jaws. These are the OPIProcSet and OPI2.0ProcSet procedure sets. The first of these deals only with OPI version 1.3 comments; the second deals with both OPI version 1.3 and OPI version 2.0 comments.
Both of these are implemented as comment dictionaries, as described in "Parsing comments"When installed in CommentDict they capture any OPI comments in the PostScript language document, and if a high resolution image can be found on disk, they substitute this for the low resolution proxy image, and skip the proxy before continuing to process the remainder of the document. Because this support for OPI is implemented as a comment dictionary, it only applies to PostScript language documents; OPI forms in PDF files are treated like any other form object, and no image substitution takes place.
To use either of these procedure sets, you must first load it into memory using findresource. findresource returns a dictionary containing a number of procedures and the comment dictionary itself. It is up to you to install the comment dictionary at the appropriate time, and if necessary merge it with any other comment dictionaries you wish to use (remember that setuserparams overwrites any existing comment dictionary, it does not merge dictionaries). If, for example, you have no other comment processing, then to enable OPI processing for a particular document, execute:
/OPI2.0ProcSet /ProcSet findresource
/CommentDict get mark exch /CommentDict exch >> setuserparams
before the start of the document (assuming you want OPI2.0ProcSet and not OPIProcSet).
You can find the code for these procedure sets in the resource files %resource%ProcSet/OPIProcSet and %resource%ProcSet/OPI2.0ProcSet. The mapping of PostScript language file names to operating system file names is described in the platform-specific sections of the documentation.
The comment dictionary for OPIProcSet, which is simpler because it only has to deal with one set of comments, looks like this:
/CommentDict <<
/ALDImageFileName {/ALDImageFileName OPIdocomment}
/ALDImageID {/ALDImageID OPIdocomment}
/ALDImageDimensions {/ALDImageDimensions OPIdocomment}
/ALDImageCropRect {/ALDImageCropRect OPIdocomment}
/ALDImagePosition {/ALDImagePosition OPIdocomment}
/ALDImageColor {/ALDImageColor OPIdocomment}
/ALDImageColorType {/ALDImageColorType OPIdocomment}
/ALDImageTint {/ALDImageTint OPIdocomment}
/ALDImageTransparency {/ALDImageTransparency OPIdocomment}
/ALDImageGrayMap {/ALDImageGrayMap OPIdocomment}
/BeginObject {pop OPIdoobject}
>>
Most of the procedure just calls OPIdocomment to store the comments away until the BeginObject comment, when they are needed. The procedures OPIdocomment and OPIdoobject are both defined by the procedure set's
Initialise procedure, which is automatically executed when the procedure set is loaded into memory by findresource:
/Initialise {
userdict /OPIinitialised? known { userdict /OPIinitialised? get
} {
false
} ifelse not {
currentglobal false setglobal userdict /OPIdocomment {
exch OPIdict 3 1 roll
1 index dup length string cvs anchorsearch pop pop (: ) anchorsearch pop pop put
} put
userdict /OPIdoobject {
/OPIProcSet /ProcSet findresource begin DoObject end
} put
userdict /OPIdict 12 dict put userdict /OPIinitialised? true put setglobal
} if
} bind
The OPIdocomment procedure strips the leading part of the comment off using anchorsearch and then stores the variable data from the comment in OPIdict with a key name matching the original comment. The OPIdoobject procedure just executes DoObject to render the image, based on the information previously gathered in OPIdict.
/Known {
2 copy known {
1 index exch get true
} {
pop false
} ifelse
} bind
The convenience procedure Known is used to quickly check whether a key is present in OPIdict (that is, whether a particular comment has been seen) and if so, return its value.
The next procedure, findfile, is important because it is the one procedure in this set which can usefully be changed by an OEM.
%%
%% OPIdict filename => OPIdict paramsdict file true
%% See the manual before adding file types to this procedure.
%%
/FindFile {
mark {
8 dict
2 index dup 0 get 16#28 eq {cvx exec} if
(r) file 1 index /TIFFDecode filter
} stopped { cleartomark false
} {
4 2 roll pop pop true
} ifelse
} bind
It is called with two operands on the stack: OPIdict and a string containing the file name. If successful, it returns four results: OPIdict, an image parameter dictionary, an open file object, and the value true. If unsuccessful, it returns the two operands unchanged and the value false.
This procedure should attempt to locate the file whose name is given. It should identify its type, open it, and parse enough of the file header to produce a valid parameters dictionary. DoImage will provide much of the information in the actual image dictionary, but the parameter dictionary returned by FindFile should contain values Width, Height and BitsPerComponent.
The default version of FindFile assumes that the file name passed to it is correct, and that the image file itself is a TIFF file that can be read by the TIFDecode filter.
Note: File names in DSC comments may be either a plain file name or a PostScript language string enclosed in parentheses (for example, if the actual file name contains spaces).
The code:
2 index dup 0 get 16#28 eq {cvx exec} if
is used to "unquote" the string in the second case, and you should do the same in any version of FindFile you write for yourself.
The filename operand passed to FindFile is taken directly from the ALDImageIID comment, or if that is not present, from the ALDImageFileName. No processing of the file name is done, which is why you need to check whether it is enclosed in parentheses or not. If you need to know which comment the file name original came from, you will need to inspect OPIdict yourself to see which key exists. This file name will often not be suitable for passing to the file operator, depending on the precise nature of the environment in which you are working. The simplest form of processing you might want to add to your own FindFile procedure is to add a file device name to the beginning of the string containing the file name, so for example if the OPI comments described a file foo, you would pass a file name of the form %opi%foo to the file operator. Of course, the file device %opi% is normally not defined in Jaws, but you can add a definition of it so that it describes a directory which Jaws shares with your OPI server. Another alternative might be to write a version of FindFile which searches in several directories looking for the correct file name, or which adds file name suffixes according to some inhouse conventions.
The other change you might want to make to FindFile is to add the ability to handle other kinds of file. You will need to add code to identify files (and fail gracefully if the files appear to be corrupt), parse the header and create the parameters dictionary result, and open and return the file object result. If the data in the disk file is already in a form suitable for use as a DataSource in an image dictionary, you can return the file you just opened positioned at the beginning of the image sample data. If the data in the disk file is interleaved in some way, you may need to return a filter file object whose data source is a procedure which reads samples from the disk file and packs them appropriately for the image operator.
Although the TIFF specification does not make any provision for vector formats such as Encapsulated PostScript language files, you can handle these as well. Obviously, you will have to place dummy values in the image parameters dictionary to prevent errors, but you can also create a key ALDImageOperation in this dictionary. If this is present, it may contain a string, file or procedure, which will be executed instead of the image operator. When it is executed, both the parameter dictionary returned from FindFile and the image dictionary which would have been passed to image or imagemask are on the dictionary stack. The file to be rendered, as returned by FindFile, will be
the DataSource entry in the image dictionary, and the CTM in the graphics state will have been set up to render an image placed according to the ALDImagePosition, ALDImageDimensions and ALDImageCropRect comments in the original file. Depending on the vector format in use, you may need to make changes to the graphics state, or consult other entries in either OPIdict or the image dictionary before rendering the file. Both dictionaries should be popped from the dictionary stack before returning. The procedure DoImage performs the detailed work of setting up the image, and is shown in an abbreviated form here. It should not be necessary to make any changes to DoImage.
/DoImage {
exch begin
8 dict begin
/ImageType 1 def
/Width Width def% Collect parameters from FindFile dictionary
. . .
gsave
dup /ALDImagePosition get cvx exec
. . .% Calculate CTM for image position dup /ALDImageDimensions get cvx exec
. . .% and for image cropping
2 index /ALDImageCropRect get cvx exec
. . .
/ALDImageOverprint Known {cvx exec setoverprint} if Photometric 2 lt {
. . .% Handle coloured grayscale images and masks BitsPerComponent 1 eq {
. . .% Handle image masks
} if
/ALDImageColor Known {cvx exec} {0 0 0 1 (Black)} ifelse
. . .% Handle spot colour images
} if
Photometric 2 eq {
. . .% Handle RGB images
} if
Photometric 3 eq {
. . .% Handle paletted RGB images
} if
Photometric 5 eq {
. . .% Handle CMYK images
} if
/ImageMatrix [Width 0 0 Height neg 0 Height] def
/ALDImageOperation Known { cvx exec
} {
currentdict ImageMask end end
{imagemask} {image} ifelse
} ifelse pop grestore
} bind
The final procedure is DoObject which ties everything together.
/DoObject {
userdict /OPIdict get
/ALDImageID Known not {
/ALDImageFileName Known pop
} if
dup type /dicttype ne { mark 3 1 roll FindFile {
{DoImage} stopped
} {
true
} ifelse
{
(%%[ OPI substitution failed; using low resolution image ]%%) = flush
} {
1 dict begin
/junk 2048 string def
{
currentfile junk {readline} stopped { pop pop
} {
not {stop} if (%%EndObject) eq {exit} if
} ifelse
} loop end
} ifelse cleartomark
} {
pop
} ifelse
userdict /OPIdict 12 dict put
} bind
This calls FindFile and DoImage to find and render the image file. If either of these fails, it prints a warning message to %stdout and continues to execute the low resolution image code in the PostScript language document as if nothing had happened. If both FindFile and DoImage succeed, it assumes that the image has been rendered, and uses readline to skip the code in the PostScript language document up until the next EndObject comment, which signals the end of the low resolution code.
The code in %rsource%ProcSet/OPI2.0ProcSet is more complex than that shown above, as it has to cope with comments conforming to both version 1.3 and version 2.0 of the TIFF specifications. However, the overall structure is the same, and the same customizations are available to you.
Output devices
Jaws supports multiple output devices. In fact each device corresponds to a particular device driver. There are a number of sample device drivers that are shipped with Jaws, but you can easily add your own special device drivers. The details of Jaws device drivers are discussed in chapters "Chapter 7" and "Chapter 10" of this manual.
The currently selected output device driver is an element of the current page device, and can be changed by calling setpagedevice. The normal rules regarding device activation and deactivation apply as described in the PLRM. If you change the current output device by calling setpagedevice while inside a gsave, the "old" output device will be deactivated but it will not be closed. In particular, any private storage required by that device driver will not be freed, so keeping a number of output devices open at the same time may consume large amounts of memory. Jaws allows you to conserve memory by sharing framebuffer memory between more than one device driver, but of course this only helps to a certain extent. In general, you should minimize the number of output device drivers which you keep open simultaneously.
You should also be aware that when setpagedevice opens a new output device, it keeps the old one open until after the new one has been successfully opened, so that there is a brief increase in the amount of memory being used.
<ac:structured-macro ac:name="anchor" ac:schema-version="1" ac:macro-id="f69a22d9-e2c6-4e88-b1ab-418f64d3d991"><ac:parameter ac:name="">bookmark58</ac:parameter></ac:structured-macro><ac:structured-macro ac:name="anchor" ac:schema-version="1" ac:macro-id="3f1bce0f-15dc-46ec-893a-c2bad5a33adb"><ac:parameter ac:name="">_bookmark59</ac:parameter></ac:structured-macro>/OutputDevice _string
The mechanism for selecting different output devices is the OutputDevice key in the page device dictionary. On some Adobe products, the value of this key is a name object which allows you to switch between a small number of output destinations, for example Printer or Fax. Jaws does not support this style of output device selection.
Instead, in Jaws the value of the OutputDevice key is a string giving the name of the output device driver as defined by a table in the OEM-specific Jaws front-end code, and an arbitrary collection of parameters to be passed directly to the driver.
For example, the simplest of the sample device drivers that ship with Jaws is the filepage driver, which implements a simple monochrome (or composite color) frame buffer device. To select the filepage driver using default values for all its parameters, execute:
<</OutputDevice (filepage)>> setpagedevice
Amongst the parameters for the filepage device are the resolution of the output device and the pixel depth. So, for example
<</OutputDevice (filepage;dpi=400;bits=8)>> setpagedevice
will open filepage and generate output at 400 pixels-per-inch and with 8-bits per pixel. The first semicolon in the string marks the end of the device driver name, and Jaws only uses the name to find the device driver. The rest of the string is completely arbitrary and is passed unchanged to the device driver for it to parse. However, all of the sample device drivers support a standardized set of parameters, separated by further semicolons, see "Chapter 7" for more information.
Naturally, no PostScript language page description should contain a call to setpagedevice with an OutputDevice key, but you may want to send PostScript language code to Jaws to open an appropriate output device at the start of each job. There are two suggested ways of achieving this.
Firstly, you can arrange to initially open a device driver which does not consume much memory. For example,
<</OutputDevice (filepage;dpi=72)>> setpagedevice
will open a device driver with little overhead and a small framebuffer (which in any case may be shared with other device drivers' framebuffers). You can place this in your initialization file, and this will be the active device driver at the start of each job. Then you can send an appropriate call to setpagedevice at the beginning of each job, which will install the device driver you want. At the end of the job, the global end-of-job restore will deactivate and close that device driver and reactivate the "default" output device established in your initialization file. (This happens because the output device is just part of the page device, and the page device is just part of the graphics state, which gets restored, like everything else in PostScript language VM, at the end of each encapsulated job.) Then, at the start of the next job, you can send another call to setpagedevice to open the desired output device for that job, and so on.
Secondly, you can use unencapsulated jobs to make permanent changes to the output device. In this case, you should send:
true 0 startjob
<</OutputDevice (filepage;dpi=600)>> setpagedevice false 0 startjob
to Jaws to change the output device. Because the change to the output device occurs in an unencapsulated job, the old device driver is closed and the new one replaces it in the outmost graphics state. After this, the new device driver is the "default" which is active at the start of every job. Individual encapsulated jobs can still make per-job changes to the output device as in the proceeding paragraph, but at the end of each encapsulated job, the global end-of-job restore will reactivate the output device that was set in the last previous unencapsulated job —(filepage;dpi=600) in this example.
Note: You should never execute PostScript language page descriptions as unencapsulated jobs. After changing the output device (or any other item in global VM) in an unencapsulated job, you must always send false 0 startjob to Jaws to finish the unencapsulated job and start a new encapsulated job.
<ac:structured-macro ac:name="anchor" ac:schema-version="1" ac:macro-id="bd2226bb-d389-4e67-a5be-3237536bfe00"><ac:parameter ac:name="">4.10_Imposition</ac:parameter></ac:structured-macro><ac:structured-macro ac:name="anchor" ac:schema-version="1" ac:macro-id="cc9bd791-f2ff-4825-bf8e-e82d2e775784"><ac:parameter ac:name="">_bookmark60</ac:parameter></ac:structured-macro><ac:structured-macro ac:name="anchor" ac:schema-version="1" ac:macro-id="2aef23df-289c-45b3-9601-1616f7e275da"><ac:parameter ac:name="">_bookmark61</ac:parameter></ac:structured-macro>h2.Imposition
Jaws provides limited support for printing multiple pages of output onto one sheet of media. This is implemented by means of the Signature page device parameter and its associated SignatureDetails dictionary.
Full support for imposition implies not only the ability to print multiple pages on each sheet of output, but also the ability to re-order the pages in the document during rendering. This is not available when interpreting PostScript language documents with Jaws, as each page must be interpreted and rendered in sequence, although as already noted, it is possible to interpret the pages of a PDF file in an arbitrary order by using the PDFpage operator or the PDFforall procedure in %lib%utils.ps. Because the facilities described in this section are implemented as part of setpagedevice, they are of course available for both PostScript language file and PDF document rendering.
Within the restriction that pages must be rendered in the order in which they are interpreted, Jaws provides the ability to automatically place a number of consecutive page descriptions on each sheet of output.
The imposition support in Jaws is intended to supplement, not to replace, the functions performed by imposition software. In particular, using this facility to combine pages from more than one PostScript language file is unlikely to succeed (although multiple PDF files can easily be combined in a single Jaws job). Using the page device dictionary entries described here allows the imposition software to translate the page over the media more easily than by using elements of the graphics state alone.
As described in the Adobe documentation, Signature is a Boolean value, and if set, it must be accompanied by a SignatureDetails sub-dictionary. A SignatureDetails dictionary must include an entry giving the Type of the dictionary, and the value of Type for Jaws must always be 99. This entry allows an implementation to spot a details dictionary that it can understand; if the details dictionary has the wrong Type, the Signature key is ignored. It is possible to provide a SignatureDetails dictionary even if the value of Signature is false—in this case the dictionary is simply ignored.
Thus, the Signature flag in the page device dictionary can be used just to turn imposition on and off, leaving the same SignatureDetails dictionary in place throughout. This is the general convention adopted by Adobe for highly product-dependent page device features—the feature may be enabled by a document that requires it, just by setting the Boolean value, but the productdependent details of the feature will have been placed in the Details dictionary (possibly by the human operator) before running the job.
The other values in the dictionary, apart from Type, describe how the imposition is to be performed. For Jaws, there are two other entries, MediaSize and Matrices.
The MediaSize entry in the details dictionary gives the overall size of the sheet on which each collection of pages is to be printed. When Signature is true, this is the value that is used to select output media, not PageSize. It is used in the same way as PageSize, and will select an appropriate media source, for a sheetfed device, or set the media size, for a roll-fed device, in exactly the same way. If no exact match is found, PageSizePolicy will be consulted, and if any page size adjustment is necessary, it will be carried out so that a page of size MediaSize will fit on the available media.
The other entry in SignatureDetails is Matrices. This is an array, and each element of this array is a 6 element array giving a transformation matrix. The number of matrices in the Matrices array gives the number of pages that will be printed onto each sheet of the media. In the example below, Matrices has two elements, so each sheet of output has two pages on it, and every second call to showpage will cause a sheet to be ejected. Each transformation matrix gives the matrix to be applied to successive page descriptions in the job. This matrix is concatenated with the default matrix so that each page is rendered in the correct place on the sheet. As with the matrices used to implement MirrorPrint and Tumble, this matrix is only used to transform graphics, and is not visible to PostScript language programs which use the currentmatrix or defaultmatrix operators.
Arbitrary transformation matrices may be used, although it is unlikely you will ever want to use anything other than a rotation by a multiple of 90 degrees and a translation. It is also possible to transform a page so that it is entirely off the sheet—one possible use for this is a SignatureDetails dictionary
which causes only the odd-numbered or even-numbered pages of a document to be printed.
No page size adjustment is ever carried out on the individual pages as they are placed on the sheet. Jaws assumes that you have set up the entries of the Matrices array with values that are appropriate for the page sizes requested by the document. This means that any PageSize requested by the document is effectively ignored.
The following example shows how you might use Signature to print letter sized pages 2-up on a single letter sized sheet. Send this to the interpreter:
<<
/Signature true
/SignatureDetails <<
/Type 99
/MediaSize [612 792]
/Matrices [
[0 -0.773 0.773 0 0 792]
[0 -0.773 0.773 0 0 396]
]
>>
>> setpagedevice
(0, 792)12(0, *396)*and then interpret the job itself as normal:.
Figure 4.3 Printing letter sized pages—2-up
Jaws keeps track of the current page on the sheet and therefore which matrix to use as part of the current page device in the graphics state. As with Duplex, any partially printed sheet is flushed during device deactivation by setpagedevice—for example, during the global end-of-job restore. This means
that, just like with Duplex, calls to setpagedevice in the middle of a document can result in unexpected page ejections and partially printed sheets. Although there is usually little reason to call setpagedevice in the middle of a document, some applications will break-up large output documents into batches of 30 pages or so, performing a complete memory restore at the end of each batch, and then re-establishing the initial conditions, including the initial calls to setpagedevice. Such documents may be unsuitable for printing with Signature.
Bit order
The contents of this section is of interest if you are going to be writing your own device drivers, or if you are going to be using the prebuilt Jaws DLL. If you are only going to use the sample device drivers to generate TIFF output on disk, this section can be ignored.
Because Jaws is portable across a wide range of machines, it can be configured for both big-endian (such as Sparc™) and little-endian (such as VAX) architecture. Jaws is normally configured to use the same ordering as the host CPU. However, this can occasionally lead to problems. The Intel architecture of the PC is nominally a little-endian architecture, but bitmaps tend to be treated in a mixed-mode order, both by Microsoft® Windows and by the TIFF file format. (When a TIFF file is produced on a big-endian machine, it has a consistent ordering; it is only TIFF files produced on little-endian machines that have this problem.)
Jaws treats a page buffer as a large array of pixels, stored in memory in scanning order, top to bottom, left to right.
For pixels whose size is a multiple of a byte (8, 24 and 32-bits per pixel), there is no ambiguity about the ordering to use: successive bytes of the image are stored in successive bytes of memory. For 24 and 32-bit pixels, the pixels are regarded as a collection of 3 or 4 8-bit samples, stored in natural order. The sample stored at the lowest addressed byte corresponds to the first named color in the SeparationOrder array (defaulting to either red or cyan, as appropriate).
For 16-bit output (16,48 or 64-bits per pixel) data is stored in the order determined by the processor (either little or big endian).
For 1 or 4-bit-per pixel images, however, there is a conflict. Jaws uses a consistent bit ordering scheme: for a big-endian architecture, the most significant bit in a word corresponds to the left-most pixel; for a little-endian architecture, the least significant bit in a word corresponds to the left-most pixel. Thus, the position of the most significant bit within a word is the same as that of the most significant nibble, which is consistent with that of the most significant byte.
For the normal interpretation of images in TIFF, the left most pixel corresponds to the most significant bit of the least significant byte of the word—a bit that is actually stored in the middle of the word!
Figure 4.4 Bit order
Because of this, versions of Jaws running on little-endian platforms reverse the bits in each byte before writing out 1-bit per pixel images to TIFF files. You need to be aware of this if you are writing your own device drivers, and check the bit ordering that your printer uses. Some interface cards can accept bytes of data with either pixel ordering, and if this is the case, you should use the hardware to reverse the bits, rather than do it in software, as this should be faster.
The following is a Jaws kernel routine that you can use to reverse the bits if necessary; the DLL version of Jaws allows you to pass a parameter to the device driver (by using OutputDevice see "/OutputDevice string") to tell it to reverse the bits before exporting them to the calling application.
void reverse_bits (unsigned char *bp, int count)
h2.Halftones
Filtering screen requests
Jaws allows you to intercept requests for halftones made by the setscreen, setcolorscreen and sethalftone operators and to override the requested screen frequency, angle or spot function.
This feature is typically useful in one of two situations. The first is if you are rendering at a different resolution to that originally intended when the PostScript language document was produced. For example, a typical pre-press screen frequency of 150 lines per inch is not much use if you are proofing to a device with a resolution of 300 dpi. Even if you are using a continuous tone output device, with no halftoning, many applications attempt to tune output (blends, for example) to match the number of gray levels that a device can represent, and if this code decides that your printer can only represent four levels (as in this example), your output will suffer accordingly. To avoid this, you can force the document to print with a more useful halftone frequency of, for example, 60 lines per inch.
The second situation in which you might want to force a particular halftone screen to be used is if you are using accurate halftones, which are described in more detail in the next section. See "Accurate screening"
The mechanism for overriding screen requests is implemented by two user parameters which are unique to Jaws, LockScreens and LockScreensDetails.
/LockScreens Boolean
If LockScreens is false, setscreen, setcolorscreen and sethalftone operate exactly as described in the PLRM.
If LockScreens is set to true and LockScreensDetails has not been set, setscreen, setcolorscreen and sethalftone have no effect. That is, the last halftone set before LockScreens was set to true will continue to be used for all rendering until LockScreens is once again set to false. This applies to all halftones, whether specified as frequency/angle/spot function or as a threshold array.
If LockScreens is set to true and LockScreensDetails has been set, setscreen, setcolorscreen and sethalftone will behave as normal, except that requests specified as frequency/angle/spot function will be modified as described below.
Requests specified as threshold arrays will not be modified and will behave as described in the PLRM.
/LockScreensDetails dictionary
LockScreensDetails may contain from one to three entries: Frequencies, Angles and SpotFunction, all of which are optional.
If a SpotFunction entry is present, its value should be a PostScript language procedure. This procedure is then used for all halftones in place of the procedure supplied as an operand to setscreen or setcolorscreen, or in a type 1 halftone dictionary. This can be used to force the use of a favorable spot function (such as the Jaws default spot function), if a job tries to use a spot function which does not work well on your device. This spot function is only used for calculating the halftone; if you execute currentscreen or currenthalftone, the result will contain that spot function that was in the original halftone request, not the one from LockScreensDetails.
If either a Frequencies or Angles entry (or both) is present, they should be arrays of numbers. The frequency or angle which Jaws will pick for the screen will be the element in this array which is closest to the frequency or angle which was requested in the call to setscreen or sethalftone. An array containing just one number will force the frequency or angle to that number.
So for example,
<<
/LockScreens true
/LockScreensDetails <<
/Frequencies [60]
>>
>> setuserparams
will make all subsequent calls to setscreen or sethalftone ignore the requested screen frequency and use 60 lines per inch instead. This could be used if you are proofing to a low resolution device, and you want to make sure that no high frequency screens are employed, while still maintaining the actual screen angles and spot functions requested in the job.
A call to setuserparams which sets the value of LockScreens to false will turn screen locking off, so that future calls to setscreen and sethalftone will function normally.
The LockScreensDetails dictionary allows for simple filtering of screen requests to be performed automatically by the kernel. By using LockScreens and "hooking" the setscreen, setcolorscreen and sethalftone operators, you can perform arbitrarily complex screen filtering, including substituting halftone dictionaries that used threshold arrays for frequency/angle/spot function requests. You might want to do this, for example, if you were licensing a set of supercell base threshold arrays for accurate screening. For information on hooking operators see "Patching operator definitions".
Accurate screening
Like other products, Jaws allows PostScript language documents to specify either "normal" or "accurate" halftones when using either a type 1 halftone dictionary or the setscreen operator.
Normal halftones are faster than accurate halftones, but allow the interpreter to produce a fairly coarse approximation of the requested screen angle and frequency. Accurate screens are typically much slower, but approximate the requested angle and frequency a lot more closely, which is necessary when producing halftoned separated color output.
The usual technology for normal screens is called Rational Tangential screening, and involves calculating a threshold array that covers a single halftone cell, where the halftone cell has been distorted so that, while still approximately the size and orientation that was requested, its corners all fall on pixel boundaries so that it can be used to tile the plane. Jaws uses this technology for normal screening.
Typically, an interpreter will implement accurate screens by intercepting the call to sethalftone or setscreen and loading a threshold array from disk which approximates the requested screen. The threshold array will typically represent a supercell approximation to the screen. The reason regular screening techniques cannot accurately reproduce standard screen angles is because they obey the restriction that each corner of the halftone cell must fall on a point with integral raster co-ordinates. Supercells attempt to relax this restriction by using the same rendering routines, but with a larger cell that contains many copies of the basic halftone cell. This means that the halftone screen can be aligned at many more different angles to the raster grid, and so any particular angle can be approximated more closely than before, although the set of
possible angles is still restricted. This approach has the advantage of computational simplicity during rendering, but at the expense of large amounts of memory during rendering, and computational expense while initially calculating the threshold arrays. Since such threshold arrays may require hours to calculate, they are usually calculated off-line and stored ready for later use.
Jaws allows you to adopt this approach, although it does not come with any suitable supercell threshold arrays and does not provide any way of calculating them. If you have access to a library of suitable threshold arrays, they can be expressed as PostScript language halftone dictionaries (typically type 6 or type 10 dictionaries), and stored as PostScript language resources in %resource%Halftone. You can then "hook" the setscreen and sethalftone operators so that calls to these operators are intercepted, and a suitable threshold array is substituted for the requested screen. For information on hooking operators see "Patching operator definitions".
Jaws can also calculate "accurate" screens immediately, using a different technology. If you set the AccurateScreens user parameter to true, or call sethalftone with a type 1 dictionary containing an AccurateScreens value of true, Jaws invokes an irrational algorithm for screening. An irrational algorithm differs from both a rational algorithm and a supercell algorithm in that (conceptually, at least), it directly samples the spot function at every pixel location on the page. This allows you to approximate any desired angle to a degree which is subject only to the precision of the arithmetic being used to carry out the coordinate calculations. Because no tile is used, there is no requirement that the halftone cell ever repeat precisely, no matter how far you advance over the raster. Irrational screening algorithms have traditionally been implemented in hardware, because of the computational expense of sampling the spot function in this way. This has also usually led to restriction of the spot function to one of a few carefully selected dot shapes, instead of the arbitrary spot functions permitted by the PostScript language.
In particular, the ranking operation on the output of the spot function that is defined for PostScript language halftones is very difficult to perform in the situation where the number of pixels centres in each halftone cell on the page varies from one cell to the other.
Regular screeningSupercellVirtual tile
Figure 4.5 Screening types
It is neither feasible nor desirable for Jaws to sample the spot function at every pixel on the page. Instead, Jaws samples the spot function once, at a higher resolution than that of the raster being used. In the current version of Jaws, this resolution is four times higher than the actual raster resolution in both x and y axes. The result of this sampling process is a prototype rectangular threshold array at the higher resolution. The important feature of this process is that the threshold array is the smallest that includes an entire copy of the halftone cell, and the array does not tile the plane exactly.
Consider that Jaws has to fill a row of pixels. The starting pixel in the row is mapped from raster co-ordinates to halftone co-ordinates, and the threshold which is closest to the pixel centre is used to color that pixel. The spot function sample point which originally gave rise to this threshold is at most 1/4 pixel in x and y from the pixel centre. Subsequent pixels in the row are colored from every fourth threshold on the same row of the threshold array. When the coloring reaches the right hand edge of the threshold array, Jaws must execute a "knight's move" back into the array to find the next threshold value to use.
This knight's move is exactly the same as that used when rendering with threshold tiles derived from rational or supercell halftones, as well as type 16 PostScript language threshold arrays. The difference is that this time the knight's move is not an integral number of pixels. Instead the length and height of the move are just the projections of the edge of the halftone cell onto
the x and y axes. Jaws uses fixed-point fractions to update the sample position, although floating point arithmetic could also be used.
Figure 4.6 Sample tracking
The effect of this process is that the sampling position is tracked to a high degree of precision, and the actual threshold used is never more than 1/4 pixel away from the actual pixel centre. Although this is not true irrational screening, it shares the ability to represent arbitrary screen angles and frequencies very closely. The position relative to the pixel grid of the red lines indicating sampling position in the diagram above varies on each of the three passes through the threshold array.
This approach has both advantages and disadvantages. The principal disadvantage derives from the small size of the threshold array compared to the size of that generated by supercell techniques. This means that there is no opportunity to perform cell balancing. This is a technique which slightly distorts the shape of all the small halftone cells within a supercell, and it is used to reduce the visibility of periodic artefacts in the halftoned output. A halftone is a regularly repeating pattern with sharp edged features. This means (regarding it as a signal instead of a pattern) that it has a substantial amount of high frequency components, and when it is sampled by the raster, frequency aliasing (also called beating) occurs. The high frequency components are reproduced at lower frequencies, and are perceived as periodic variations in the tonal level across areas which should be shaded with a constant tint. This is also called banding. Because cell balancing distorts the shape of individual
halftone cells, this means that the halftone is no longer perfectly regular. The high frequency components are "smeared out"—although the halftone pattern contains the same amount of high frequency energy, it is distributed amongst a larger number of individual frequency components, each of which has a lower amplitude. Thus the low frequency aliases are less objectionable. It is the process of cell balancing which is responsible for much of the computational expense of calculating supercell threshold arrays.
Note: An alternative description of cell balancing is sometimes given, in which the process is described as a trade-off between preserving the square shape of all the small halftone cells against ensuring that all these cells contain the same number of pixels. If the difference in the number of pixels contained in two cells is large, the difference in the proportion of "on" pixels for a given gray level is also likely to be large between the two cells, so the two cells will be perceived as having different tonal values. This variation in tonal values, viewed across the page as a whole, will give rise to periodic artefacts.
Jaws does not have the luxury of performing cell balancing, either in terms of time available to carry out the calculations, or in terms of the large number of copies of the halftone cell required to smear out the high frequencies evenly. By virtue of the fact that Jaws samples the spot function at a resolution four times higher than that of the raster, it has as many threshold values to play with as a supercell with 4 x 4 copies of the basic halftone cell, which is very small for a supercell.
Jaws does allow you to increase the size of the threshold array to cover more copies of the halftone cell, but in the current version using this to combat periodic artefacts is a rather hit-and-miss affair, as no explicit calculations are performed to mask the artefacts.
The consequence of this limitation is that the accurate halftoning in Jaws will produce good results for a smaller range of screen frequencies than a supercell approach will. Jaws is unlikely to produce acceptable results on any device if the screen frequency is more than about 10% of the device resolution. You should be able to obtain acceptable results if the screen frequency is less than about 7.5% of the device resolution. Between these two percentages, results will depend on the output device and may require some experimentation.
However, because Jaws can reproduce the requested screen angles so closely, you can actually request and get the traditional screening angles of 15°, 45°,
75° and 0° (or a rotated set, if you prefer). This greatly reduces the possibility of moiré in the final output. You may still see something that looks like moiré. You should keep in mind that the 15° separation between some pairs of screens using the traditional angles can lead to moiré in some colors, and the traditional solution of swapping two angles should work. You may also find that combining the four output plates can sometimes amplify slight banding artefacts which are present in the individual plates, making them more objectionable. In this case the solution is to go back to testing a single separation, and vary the frequency and/or angle until the banding disappears, at which point you should be able to cleanly combine the output.
The choice of spot function can also have a significant effect on the quality of the screening, particularly with regard to tonal jumps. The default spot function in Jaws is a "diamond" spot function, with the short and long axes set to values which minimize the size of any tonal jumps in mid-range tints. Jaws will reproduce any PostScript language spot function you give it, and at a low enough screen frequency, there are unlikely to be any problems with this. However, as the screen frequency approaches the upper limit at which Jaws produces usable output, you will have to exercise increasing care in the choice of your spot function.
Rendering of accurate halftones is controlled by one standard user parameter, AccurateScreens, and an extra user parameter, AccurateScreensDetails.
AccurateScreens is a Boolean which behaves in the same was as described in the PLRM—when set to true it enables accurate halftoning, and when set to false it disables it (except for type 1 halftone dictionaries which contain an AccurateScreens entry).
Note: Jaws cannot simultaneously render both accurate and regular screens. If you are specifying halftones by using a type 5 halftone dictionary, and the AccurateScreens user parameter is set to false, it is possible to construct a halftone dictionary which requests accurate screens for some separations, and regular screens for others. This is rather pointless, as it defeats the whole object of using accurate screening in the first place. Accordingly, Jaws will signal a limitcheck error if you try to do this.
AccurateScreensDetails is a dictionary which contains parameters controlling the accurate screening algorithm. All of the following parameters are optional:
/OversampleScreens integer
If present, this parameter should be a small positive integer. The default value is 1. When Jaws is constructing the threshold array and if the value of OversampleScreens is n, Jaws will divide the requested screen frequency by n and construct a threshold array covering n x n copies of the basic halftone cell. This has a similar effect to the MaxSuperScreens parameter for normal halftones, and distributes errors across a wider number of pixels. At marginal screen frequencies (that is, approaching 10% of the device resolution), trying different values for this parameter may help mask periodic banding artefacts in the output. Since no explicit cell-balancing is performed, the effect of this will vary depending on angle and resolution, so some experimentation may be required.
/Offset45 integer
The value of the Offset45 parameter is an integer between 0 and 1 with a default value of 0. The 45° screen is offset by this proportion of the cell width when it is rendered. Varying this parameter allows you to control the production of dot-centred or clear-centred rosettes, as the clear centred form is obtained by shifting the 45° screen half a cell relative to the dot centred form.
/Multiply90 integer
This is an integer, and when present has a default value of 1. The frequency of the 90° screen is multiplied by this value when it is rendered. Thus, to implement the traditional trick of increasing the frequency of the 90° screen by 8% to reduce moiré, you can set this parameter to 1.08.
Selecting screen sets
The process of selecting screening parameters for Jaws is slightly different to that for an implementation based on supercell technology.
First you must find screens which print well individually. Once you have done this, you should not have any problems combining them to produce color output.
If you are using a traditional set of angles, including 90° and 45° screens, you should pay particular attention to these two screens. These two angles yield dot patterns which are inherently periodic as you travel along a scan line of the raster. To see why this is a problem, consider a 600 dpi raster with a 55 lpi screen at 90°. The halftone cell for this screen is approximately 10.9 pixels square. Now think about where the centre of the halftone cells fall on the pixel grid—imagine that you are filling with either a very light or a very dark tint, so that the halftone dots being used are only one or two pixels across. The dots cannot be placed at fractional pixel co-ordinates, so if ten halftone cells cover 109 pixels on the page, nine of the cells will effectively be eleven pixels wide and one of them will be ten pixels wide. This will lead to a column of "narrow" cells running down the page (and similar "short" rows of cells running across the page), producing a plaid effect. If the individual halftone cells are large enough (that is, the screen frequency is low enough), this effect may be masked to a certain extent, because the variation of one pixel in the width and height of the cells is less easy to see. The effect is worst if the cells are n + 0.5 pixels across (where it produces a visual effect that looks similar to the MaxSuperScreens parameter for normal halftones), and disappears completely if the pixels are exactly n pixels across. Therefore the best choice of frequency for a 0° screen is a frequency which exactly divides the device resolution.
The 45° screen suffers from a similar problem, because it too repeats regularly across the raster grid. In this case the best value for the frequency are those for which the value of
resolution 2xfrequencyEquation hasn't copied over correctly
is an integer. This expression just gives the period of the repetition in pixels.
Observe that there are no frequencies which simultaneously work well for both the 45° and 90° screens, according to the above. However, you can use the Multiply90 parameter to adjust the frequency for the 90° screen to a suitable value.
If you find that the above limitation on these two screens is too restrictive, you may want to try rotating all four screens by a small amount, such as 7 1/2°. This is a traditional workaround which is sometimes used to combat the effect of mechanical jitter in the output device.
One set of screens which fits the above criterion at 400 dpi is a screen frequency of 28.2483 lines per inch and a value for Multiply90 of 1.1315. A job can be forced to use these frequencies by using the LockScreens user parameter described above. It is worthwhile giving the frequencies to a reasonable number of decimal places, as a small error can give rise to low frequency banding artefacts in the 45° and 90° screens. If the requested frequencies for these two screens turn out to give a halftone repeat which is within one-hundredth of a whole number of pixels, Jaws will automatically round the halftone cell size so that the repeat is an exact whole number of pixels. No such rounding is performed for oblique angled screens.
Halftones—dispersed dot screening
Both normal and "accurate" halftones can be described as clustered dot screening algorithms, in which as pixels are progressively colored, they form larger clusters on the page. Such halftones are suitable for use on a wide variety of output devices. An alternative approach is dispersed dot screening—sometimes called FM (Frequency Modulated) screening—which is when the colored pixels are scattered across the page. This approach is not suitable for some devices, as it requires the ability to faithfully reproduce individual pixels on the paper.
Figure 4.7 Clustered and dispersed dot screening comparison
Many dispersed dot algorithms are either error diffusion or stochastic processes; these produce high quality screening at the expense of computational complexity.
As with supercell techniques, these require a great deal of care to avoid visible artefacts, and need to be calculated off-line, and then presented to the PostScript language interpreter as threshold arrays. Although Jaws supports external threshold arrays, no such arrays are shipped with Jaws.
Jaws also includes a built-in method for dispersed dot screening that generates the threshold arrays on the fly. The halftones that Jaws generates in this way have more low-frequency content than those generated by off-line tools, which can lead to more visible artefacts, particularly in large areas of constant color. However, unlike halftones generated from fixed threshold arrays, the patterns produced do not repeat evenly across the page. The repetition produced by fixed threshold arrays can be visible on the page, especially in highlights. Jaws generates a collection of smaller tiles and places them on the page in a pseudo-random order which can break up this visible periodicity.
The FM screening has been implemented in the interpreter as a type 99 halftone dictionary. Thus you can use it with any device driver, and (by judicious use of the LockScreens user parameter) with any job.
There are currently two entries in the halftone dictionary for a type 99 halftone.
/DotSize integer
DotSize controls the size of the individual dots in the tile. All the dots are the same size. In the present version of the algorithm, DotSize must be an integer with the value 1 or 2. A value of 2 indicates that each dot is a 2 x 2 pixel square. This is useful for devices that have trouble imaging a single pixel. DotSize must always be present in the halftone dictionary.
/FlushTile Boolean
FlushTile is an optional Boolean entry. The default value is false.
Normally, Jaws uses the same virtual tile on every page, as seeding the tile with random numbers is a comparatively expensive operation, and for low resolution output devices it can add an appreciable amount to the time taken to render each page of output. However, for preseparated color jobs, where each page of the job represents a different plate, using the same tile for each plate can potentially lead to unwanted correlation between dot positions on different plates (for example, if there are large areas of flat color on the page).
If you set FlushTile to true, Jaws will generate a fresh tile for each page of output.
If you are using a device driver like filebandseparation to generate separated output from a composite color PostScript language file, you have the option of either using a type 99 halftone dictionary with FlushTile set to true, or alternatively using a type 5 halftone dictionary with a separate type 99 dictionary for each separation. If you are using a device driver like filebandcolour, you must use a type 5 dictionary if you want a different tile for each separation, because when the separations are being produced simultaneously there is no opportunity to generate a fresh tile between each separation.
Using FM screening with a type 5 halftone dictionary can require large amounts of extra working memory during rendering (just as accurate screens do). (For a dot size of 1, you will need approximately 0.5 MB per separation; for a dot size of 2, you will need 1 MB per separation.
A type 99 halftone dictionary may also contain a TransferFunction entry, just like any other halftone dictionary.
Here are some examples of using type 99 dictionaries.
The first example sets up a simple type 99 dictionary that is suitable for rendering monochrome output. No transfer function is used (other than those which may be set in the graphics state).
<<
/HalftoneType 99
/DotSize 1
>> sethalftone
The second example sets up a type 99 dictionary suitable for generating color separations. In this example, a simple gamma correction transfer function is used, and, as per the PLRM, will override any transfer functions that may be set in the graphics state.
<<
/HalftoneType 5
/Cyan <<
/HalftoneType 99
/DotSize 1
/TransferFunction { dup 0 ne {.65 exp} if}
>>
/Magenta <<
/HalftoneType 99
/DotSize 1
/TransferFunction { dup 0 ne {.65 exp} if}
>>
/Yellow <<
/HalftoneType 99
/DotSize 1
/TransferFunction { dup 0 ne {.65 exp} if}
>>
/Black <<
/HalftoneType 99
/DotSize 1
/TransferFunction { dup 0 ne {.65 exp} if}
>>
/Default <<
/HalftoneType 99
/DotSize 1
/TransferFunction { dup 0 ne {.65 exp} if}
>>
>> sethalftone
Because the pixel patterns used in type 99 halftones are calculated on the fly, their power spectrum is not as good as those of FM halftones using threshold arrays that have been calculated off line (which typically takes many minutes to do). Type 99 halftones are certainly good enough to use with 4-bit per pixel devices, but may show graininess when used with 1-bit per pixel devices.
The power spectrum refers to the way halftones are calculated. A good halftone would have a flat power spectrum, that is the "power" would be the same no matter what gray level you use.
High quality calculations can achieve this, but this uses lots of computer processing. When calculating, on-the-fly shortcuts are used to reduce the processing time. This leads to less than perfect screens, and visible artefacts in the output.
This is more clearly exhibited in graduated tints, as "steps" in regular screens. For FM screens, the pseudo-random distribution of the individual pixels tends to form clumps around certain values, making those values appear "denser" than they should be.
Type 99 halftones are not currently supported by the 8-bit per pixel composite color raster routines (that is, halftoned 8-bit rasters, not continuous tone 8-bit rasters). Most of the sample device drivers do not use such rasters, except for XSimple. If you attempt to perform output to such a raster with a type 99 halftone set, you will get a limitcheck error.
PostScript language parameters specific to Jaws
Jaws uses the system, user and page device parameter dictionaries to control a number of product-specific features. The parameters described below are specific to Jaws and even if they are present in other products will probably function differently.
System parameters
There is one system parameter specific to Jaws:
/KernelBuild string
It is often useful to be able to distinguish a particular build of the Jaws libraries, as opposed to a particular build of your own software. The BuildTime system parameter is an integer reflecting the time at which your own software was last built, as described in the PLRM. The KernelBuild system parameter is specific to Jaws and contains a human-readable ASCII string giving the date and time at which the libraries linked into this version of the software were built. Like BuildTime, this parameter is read-only. You should always quote the value of KernelBuild when reporting bugs in the kernel libraries.
h3.User parameters
Jaws includes the following special user parameters:
There are a few extra user parameters, over and above those defined in the PLRM. Most of these are Boolean parameters which are used to enable or disable specific features, and as such represent either "compatibility switches" or attempts to fix problem jobs on the fly.
For the full list and descriptions of the available user parameters see the HTML documentation supplied with the Jaws SDK.
Page device parameters
There are no page device parameters specific to Jaws which are handled by the kernel, except for the product-specific interpretation placed on the OutputDevice and Separations parameters, see "Output devices" and "Color overprinting"and for more information.
Of course, your own device drivers are permitted to add arbitrary page device parameters. The mechanism for doing this is described in "Chapter 10"