Raster output from the RIP is sent to the application through the raster backend API. Most of the configuration for how rasters are presented to the API is determined during the job configuration stage of processing a job, using parameters to the PostScript setpagedevice
call. The raster backend selected receives API calls during interpretation of the job that can be used to prepare for the data that will be received and make some minor modifications to how it will be presented, and calls during rendering to deliver the raster data.
The application layer is responsible for selecting the raster backend API implementation to use. Different raster backends are usually used in cases where multiple output formats are supported, but may also be used to select backends for performance testing and debugging, or other reasons.
There are a number of important concepts and structures to understand when working with raster data and raster backends in the Harlequin RIP.
The Harlequin RIP constructs one or more display lists for each page that it interprets. A display list is an internal data structure that represents the visible content of the page, with the page objects converted into a form suitable for the renderer to operate on. The Harlequin RIP will render a display list when the page is complete. The display list structure that the Harlequin RIP uses is divided into regular bands, horizontal slices across the width of the raster output. The size of a band is very important:
Global Graphics have found that it is generally good for performance to keep the total memory for bands being rendered within the processor's L2 cache size, allowing some overhead for other working data structures, but also that the best way to determine band size for your RIP integration is to test with a range of band sizes on typical workflows.
The Harlequin RIP Extensions Manual documents methods to control the size of bands in the display list. The raster backend implementation can also influence the maximum size of bands, band memory alignment, and how bands are allocated.
The Harlequin RIP always renders an entire display list at a time. The Harlequin RIP may perform multiple render passes over a display list, or multiple render passes over a single band in a display list. There are a few ways in which this may become visible to you:
The Harlequin RIP supports a considerable number of different raster output formats, each with different numbers, interleavings, and depths of data channels. The raster backend API uses a very general hierarchical data RASTER_LAYOUT structure to describe the layout of the raster data. Most of the raster backend API calls are presented with a pointer to a raster layout structure, and the core library provides calls to acquire and release references to raster layout structures, to copy, serialize and deserialize them, and to modify some aspects of them and compare some sub-structures. The RASTER_LAYOUT structure is intended to provide sufficient information and to be sufficiently general that your code can refer to it directly when needed.
Two common formats that the RIP may be configured to render output in are separations with one color per band; or as a composite with multiple colors in the each collected set of bands; but there are other layout combinations possible. In any case, the RIP outputs the bands represented by the RASTER_SHEET sub-structure as a single collection. There may be multiple raster sheet sub-structures in the entire raster layout, representing different separations of a page. The raster backend API's RASTER_START_EX and RASTER_FINISH_EX calls encapsulate output of each separation.
Another important level to understand in the RASTER_LAYOUT hierarchy is the RASTER_PLANE structure. At this level in the hierarchy the channel(s) represented by a plane are stored in a contiguous block of memory. The data in a raster plane represents a block of consecutive pixels across a number of lines. Each pixel may have one or more channels of data for it, depending on how the RIP was configured. The RASTER_PLANE and other RASTER_LAYOUT structures provide separate pixel and line strides, offsets, and storage width information to unpack or manipulate the raster data without needing to repeat the calculations the RIP performed to construct the raster.
The raster layout structure describes the structure of the raster for a page generically; the same structure will be generated for pages with the same size, output configuration, and band structure. It does not contain information that is specific to any particular instance of a page or job.
The Harlequin RIP treats the lines of raster data in bands it is outputting for each sheet as a continuous sequence over all frames in each sheet. You may need to convert these line numbers to frame indices within a sheet, and band indices within a frame. The raster layout contains fields that provide easy access to both the number of lines and bands at each level of the hierarchy, but also the total size of the raster data required ignoring separation omission, and the total size of the raster data rendered with separation omission.
The RasterDescription structure is passed to many of the raster backend API calls. Unlike RASTER_LAYOUT, this structure is very specific to the job, page, sheet, and band that is being rendered. This structure is the first place to go to find data that may be useful or relevant in identifying what output is being rendered. In particular, the job name, job number, page numbers (in various different forms), and current rendered band offsets are presented in this structure.
Raster descriptions may be packed using RasterDescriptionPack(), which can be used to serialize a raster description into a contiguous block of memory. Non-pointer fields in packed raster descriptions may be accessed, but pointer fields must not be dereferenced. Packed raster descriptions may be unpacked using RasterDescriptionUnpack(), deserializing them into a new memory allocation. Pointer fields in unpacked raster descriptions may be dereferenced safely. Unpacked raster descriptions must be destroyed when they are no longer needed using RasterDescriptionFreeUnpacked().
The current RASTER_SHEET in a raster description that is being used for rendering may be retrieved using RasterSheetFromDescription(). This is a simple convenience function that uses the raster description's sheet index to look up the sheet layout in the raster layout.
Harlequin VariData can significantly speed up processing of variable data PDF jobs. If you intend to use External Harlequin VariData (eHVD) you need to understand eHVD elements and backgrounds, and the relationship between elements and the rasters produced for them.
Some of the calls to the raster backend API are made while interpreting pages (for example, when the setpagedevice
call is invoked to change page size, or when a new spot color is detected and a dynamic color separation is added), and some calls are made either just before or while rendering the page. When using Harlequin Parallel Pages, the RIP may be interpreting the next page in the job while it is rendering a previous page. Implementors need to be aware that calls to some of the API entry points may be made from both the interpreter and renderer but referring to different pages, and avoid performing operations during the interpretation calls that might disrupt simultaneous rendering operations.
The relationship between the output raster bounding boxes, margins, and output raster size are shown below:
The image width and height, margins, and page relative bounding box can all be accessed from the RasterDescription structure. RasterDescription::imageWidth and RasterDescription::imageHeight are the actual size of the output raster, in pixels. The output raster size may have been restricted from the page raster set by the job or configuration if the /ImagingBBox
and/or /TilingBBox
keys were applied in the pagedevice (for example, when tiling output). The RasterDescription::pageRelativeBBox array gives the offsets from the output raster to the page raster, measured in pixels. The RasterDescription::leftMargin and RasterDescription::topMargin are offsets to the output raster from the output device's reference point: you would normally configure /LeftMargin
and /TopMargin
in the page device to shift the page raster past the unprintable area of a device. As presented in RasterDescription, the left and top margins include any extra translation resulting from restricting the page raster. The RasterDescription::rightMargin and RasterDescription::bottomMargin are offsets from the output raster to the other edge of the unprintable area of a device. The come from the /RightMargin
and /BottomMargin
configured in the page device, adjusted by any additional size from restricting the page raster.
If your application will only ever use one raster output backend, then you can select it during startup using the SDK's SwLeSetRasterAPI() call.
If your application supports multiple raster output backends, the method recommended to is to select the raster backend based on the page device's /PageBufferType
parameter. A more detailed implementation of the callback method presented in the startup section is explained here.
Raster backend API instances are registered using the RDR API as instances in the RDR_NAMES_RASTERAPI namespace. The SwLePgbSetCallback() function is used during startup to register a callback that will select a raster backend when /PageBufferType
is changed in the RIP's pagedevice configuration:
The callback function used to select the raster backend interprets the pagebuffer parameter as a string, looks it up in RDR, and calls SwLeSetRasterAPI() to select it:
This is the method that the "clrip" application uses to select raster backends. Backends built into the "clrip" application are documented in Raster output backends.
/PageBufferType
parameter will change (it may not be exposed in the SDK).The raster backend API is represented by a structure of function pointers, called by the SDK library in response to RIP actions. A backend implemented to this API will receive calls from the RIP:
NULL
RasterDescription parameter; calls before rendering each sheet will have a valid RasterDescription parameter.Most of the raster backend API calls provide access to a structured data parameters pointer. Structured data parameters provide a method for the core library to pass relevant parameters directly to your raster backend, allowing you to modify the behavior of your raster backend based on user configuration.
Structured data raster parameters may be set during a setpagedevice
call, or by using the setrasterparams
pseudo-operator. In a setpagedevice
call, the raster parameters are set as a sub-dictionary of the /RasterParams
dictionary:
The name used inside the RasterParams
dictionary must match the /PageBufferType
value used to select the raster backend exactly. If the raster backend is overridden using some other method (e.g., the "clrip" -o
option) or an alias is used, the raster parameters will not match. You may set raster parameters for raster backends that are not active, and select the raster backend later. You may also set raster parameters for multiple raster backends at the same time, each using the name it would be selected with /PageBufferType
. When setting raster parameters during setpagedevice, the raster parameters will replace any previous parameters for the raster backend.
The PostScript setrasterparams
pseudo-operator will set a dictionary of raster parameters for a raster backend, or merge them into an existing dictionary if parameters are already set. setrasterparams
takes a dictionary and an optional raster backend name. The name, if present, is the PageBufferType
used to select the raster backend. If the name is not present, then the current value of PageBufferType
will be used:
The dictionary of raster parameters will be merged into any existing raster parameters for the named backend, replacing any parameters with the same name. The new set of raster parameters will be provided to the next call to the raster backend (setrasterparams
operates immediately, not on a pagedevice change).
Raster parameters set through setpagedevice
and setrasterparams
are subject to PostScript's save and restore.
The raster backend API band size call, the raster requirements call, and the blank page call all provide access to structured data raster parameters through their RASTER_BANDSIZE::raster_params, RASTER_REQUIREMENTS::raster_params, and RASTER_BLANK::raster_params fields. The raster output start, raster output write, and raster output finish calls provide access to structured data raster parameters through the RasterDescription::rasterParams field. The raster destination and job end calls do not provide direct access to structured data raster parameters, but access can be managed by either unpacking raster parameters in a previous call, or retaining and releasing the raster parameters appropriately.
The structured data raster parameters are represented using the structured data callback API. This API provides an abstract type sw_datum to represent data stored as dictionaries (that is, lookup tables), arrays, or the primitive types integers, real numbers, Booleans, strings, or the null value.
In all the calls where a raster backend function is presented with a sw_datum object, the object is only guaranteed to be valid for the duration of the function call. If you wish to refer to parameter values in other callback functions or threads, you must either:
Before using the structured data API, you must get a pointer to the API implementation from RDR. If you are linking to the static SDK library, then this has already been done for you, and stored in a global variable. The SDK provides a utility function GetDataAPI() which will retrieve and cache the API pointer for you. As of Harlequin 14, this function is expected to return a non-NULL
value. In previous RIPs, it may return NULL
.
The raster parameters pointer provided in the raster backend API calls may be NULL
if there are no raster parameters set for the corresponding /PageBufferType
.
Raster backend code should test that both the API pointer and raster parameters pointer are valid before unpacking parameters, and set sensible default values in case parameters are not provided.
The structured data API contains methods to get values from dictionaries (sw_data_api::get_keyed()), to get values from arrays (sw_data_api::get_indexed()), to iterate composite objects (sw_data_api::iterate_begin(), sw_data_api::iterate_next(), and sw_data_api::iterate_end()), and to match and typecheck multiple keys in a dictionary (sw_data_api::match()).
If you are just unpacking a single raster parameter, then the sw_data_api::get_keyed() method is most likely to be useful. When using this method, you should test there was a parameter value retrieved, whether it is correct type, and if it has a suitable value:
If you need to unpack several raster parameters, then the sw_data_api::match() function can reduce the amount of testing you need to do, by encoding whether keys are required or optional, and the possible types allowed for the value:
Matched keys may have multiple different types, see the structured data API for details. Structured data raster parameters may have nested dictionaries and arrays.
The RIP normally allocates band buffers from its own memory pool. Your raster backend can change how band buffers are allocated by modifying the RASTER_REQUIREMENTS::have_framebuffer field in any of the raster requirements calls that happen during interpretation. You may not change how band buffers are stored in the raster requirements calls that occur during rendering. The values you may set this field to are:
With BAND_ALLOC_SKIN your raster backend can still take control of allocating raster output bands itself in cases where you cannot allocate and retain a full framebuffer. This may be useful if you have requirements for placement of raster bands in particular memory locations (e.g., locations where hardware DMA can access data, or memory shared with other processes).
If your raster backend takes responsibility for allocating bands, it must guarantee to provide a specified minimum number of bands simultaneously. The minimum number of bands you must provide can be found in the RASTER_REQUIREMENTS::minimum_bands field, the value depends on the number of threads that will be used for rendering, and on any halftone modules in use. If you fail to provide this number of bands simultaneously, the RIP may deadlock waiting for bands to become available.
Managing two-pass compositing or partial paint is trickier if you are managing band allocation yourself. Your raster backend will not receive raster band write calls during compositing or partial paint render passes, but it will be asked to allocate bands. You need to know when the RIP has finished using the data it stores in the band memory so that you can release those bands. This can be determined by registering an event handler for the SWEVT_BANDS_HANDLED event, and looking in the associated SWMSG_BANDS_HANDLED event message until you see a message with a line range that includes the last line of the band and has the SWMSG_BANDS_HANDLED::final boolean set to TRUE
. The lines in the SWMSG_BANDS_HANDLED ranges are measured in a continuous sequence across all frames of the sheet being rendered.
If you need to allocate band buffers (or other large buffers) from the MPS arena (using SwAlloc() or MemAlloc()), Global Graphics recommends doing so during interpretation in the raster requirements call; however, care should be taken because this function is typically called multiple times during page initialization as various configuration items change the page dimensions.
Allocating memory in the raster output start call is not recommended, because the SDK only calls it when the first band is output to a page. At this point, even if the interpreter might have allocated large amounts of memory, and all available core memory may have been allocated for the band buffers. Allocating memory in the raster destination call is not recommended either, because there is no error return path to the RIP. The RIP requires that call to return a memory address that it will write data into. If an allocation fails during rendering, there are very few low-memory strategies available, so a failure is likely to raise an error and abort the job. In contrast, for allocations made in the raster requirements call, Harlequin may apply a number of different low-memory strategies to ensure that the job can run to completion.
The SDK library provides support functions to help you implement raster output using framebuffers. The framebuffer support code enables the use of custom allocators, so framebuffer memory can come from process memory, shared memory, or your own source. Framebuffers can be acquired, released, reused between pages, and also removed from management so you can pass them to downsteam raster processing stages asynchronously.
See SDK support for framebuffer raster output.
The raster backend API calls are all provided with a generic data pointer. This generic data pointer is passed through from the job context parameter supplied to inputq_print_job() and to the low-level SwLeJobStart() function. You can use this parameter to pass through a job object reference from job submission to rasterization.
The core library contains a library to simplify eHVD support is raster output backends. The SDK library extends that support to enable compositing and outputting eHVD output through the same raster backend interface as non-variable jobs.
See Enabling eHVD in Raster output backends.
During interpretation, the raster backend interface's sw_raster_api_20230105::blank_page_fn function is called when a page is omitted entirely. Pages can be omitted because:
The raster backend implementation may decide what action to take for a blank page, depending on your requirements:
The raster backend blank page function may modify the value of the RASTER_BLANK::action field to indicate which action should be taken.
When using the Scalable RIP raster manager, blank pages must either be rendered or counted, they cannot be removed. It is the raster backend's responsibility to detect this case and act accordingly. The Scalable RIP raster manager will only be active if the raster manager API is registered in RDR. You can test this using the SDK's get_skin_api_ptr() function. The "clrip" application wraps this test into a function that tests if the API is registered, and caches the result. This will not change during the lifetime of the RIP:
See Enabling the Scalable RIP raster manager for details of ripfarm_report_raster() as well. Note that the number of tiles must be overridden when reporting blank pages to the raster manager, so that it expects the right number of pages. Blank pages are not tiled.
The Scalable RIP raster manager must be explicitly enabled in the Scalable RIP configuration JSON if required, by setting the UseRasterManager
parameter to true
.
The Harlequin RIP can optimize the amount of data sent to the raster output backend by omitting bands of data that are empty. Trimming data can be turned on by setting the TrimPage
boolean in the page device configuration:
Bands may be trimmed if they are empty, even if they are not zero. If you have configured a page background color using /EraseColor
in the page device, then bands with no content will be trimmed, even when the channel data for the page background is non-zero. It is the raster backend's responsibility to reconstruct empty bands with the right background color if required for downstream processing.
The raster backend can determine whether to allow trimming, and how it operates by setting the RASTER_REQUIREMENTS::write_empty_bands field during the raster backend's raster requirements function. This field can be set during any raster requirements call until the first call during rendering a page (i.e., with a valid RASTER_REQUIREMENTS::render_type field but a NULL
RasterDescription). The same value should be used for the subsequent rendering calls on that page. The values the field can take are:
Trimming can be detected in the raster backend by examining the RasterDescription::trim_page boolean. If this is true
, then the actual raster data provided may be less than the raster height indicated. The start and end of the bands that can be trimmed are provided even if trimming is not active. The RasterDescription::trim_start field indicates the first line of the raster that is actually output (or would be output if trimming is disabled), and the RasterDescription::trim_end field indicates the last line of the raster that is actually output (or would be output if trimming is disabled). Trimming operates on whole bands at a time, so these are the start line of the first band output and end line of the last band output respectively.
If the entire page is trimmed out, then the trim start will be greater than the trim end (the trim start will be the page height, and the trim end -1
). In this case, the blank page handling function will be called to determine whether to output the page. If it indicates the page should be rendered, the raster output start function and the raster output finish functions will be called, but there will be no band output calls in between them. You may need to detect this case in your raster output start or finish function, and construct a blank page or placeholder if required for your downstream processing.
The Harlequin RIP may be configured to render a subset of the colorants in the process color model, and to omit blank separations. Details of how to configure separation controls are in the Extensions Manual.
If the RIP is configured for separation omission, the raster backend will only get calls to output separations that contain marking content. The total number of separations produced, and the separation indices provided in the RasterDescription structure are adjusted to include just these separations. The raster layout structure contains the full set of separations (sheets) that would have been produced, along with their output ordering, and indices and totals noting which separations will be output and which separations will be omitted.
If all separations for a page are omitted, the blank page function will be called. The raster backend can choose whether to count the page in the page output numbering sequence, or whether to ignore it.
The Harlequin RIP normally outputs bands synchronously. The RIP makes a call to output a band, the raster backend processes the band, and then the RIP continues. The RIP can also perform asynchronous band output, where the RIP makes a call to output a band and then continues to render the next band while the raster backend processes the output band. This can improve performance if the raster backend has a slow processing step or stores or transmits the raster data using a slow I/O method, and can reduce latency between band output calls. There are a few steps to enable asynchronous raster output in a raster backend:
The RIP must be configured to allocate extra bands. If there is no band available to render the next band while a raster backend is processing asynchronously, then there will be no performance improvement. The RIP can be configured to allocate extra bands by setting the boolean /DynamicBands
system parameter to true
.
How many extra bands to allocate can be controlled if necessary by using the DynamicBandLimit
system parameter. This can be used to limit the number of extra bands (setting it to a positive integer) or the size of extra bands (the absolute value of a negative integer, in KB). The default value of zero allows the RIP allocate as many extra bands as it wishes.
The RIP needs at least one extra band available in order to make asynchronous output useful.
Tell the RIP that the raster backend will be processing bands asynchronously. You can do this by setting the RASTER_REQUIREMENTS::bands_handled_by_caller boolean to false
in the raster backend's raster requirements call. This indicates that the RIP (the caller) will not take responsibility for issuing the SWEVT_BANDS_HANDLED event that is used to signal that a band's output is complete.
Note that the RIP or SDK may override this request if it is taking responsibility for band storage itself (for partial paint or two-pass compositing), but in these cases your raster backend will not receive raster output write data calls.
RasterDescription::band.y1
) and the number of lines in the band (from RasterDescription::band.y2 - RasterDescription::band.y1
) in your queue. These will be needed to generate the SWEVT_BANDS_HANDLED event when processing of the band is complete.Inform the RIP when band memory is no longer needed. When asynchronous processing of an output band is completed, you must inform the RIP about it. If the RIP is allocating band memory, this allows the RIP to re-use the memory allocated for another band. To inform the RIP that processing an output band is complete, the asynchronous output thread should issue a SWEVT_BANDS_HANDLED event, with an associated SWMSG_BANDS_HANDLED message containing the band owner saved from RasterDescription::band_owner and the range of lines for the band. The message should also have the SWMSG_BANDS_HANDLED::final boolean set to TRUE
to indicate that it is truly finished with the band memory:
The lines in the SWMSG_BANDS_HANDLED ranges are measured in a continuous sequence across all frames of the sheet being rendered.
The "clrip" application layer contains examples of asynchronous output in raster backends.
The Harlequin RIP normally outputs bands in order, from top to bottom of the page. If your raster backend can accept bands in any order, then the RIP can be configured to output bands in arbitrary order. This can improve performance for multi-threaded rendering. This is commonly done when using framebuffer output. The band output order can be changed in the backend's raster requirements function by setting the value of the RASTER_REQUIREMENTS::band_order field to BAND_ORDER_ANY.
The raster backend is provided with several different page number fields in the RasterDescription structure. These can be confusing if not used as recommended.
The output page number is the number of the page in the output sequence for a job, starting from 1. Blank pages are normally not included in this sequence, however the raster backend blank page function can be used to alter that behavior, and either output blank pages, or include the blank page in the output page number sequence but not actually output a page. The output page number should always be calculated by adding RasterDescription::pageNumber and RasterDescription::pageNumberOffset together. Do not try to use RasterDescription::pageNumber on its own: when using Scalable RIP, or multiple pdfexecid
calls, or a number of other circumstances, it is incomplete.
The PDF page number is a 1-based page number for pages from PDF jobs. This is useful to determine the corresponding page from a PDF job even after selection by PageRange
and reordering by PageOrder
in the PDF parameters. The PDF page number also enables you to determine if a page is a blank inserted as part of a PageOrder
block. The PDF page number is stored in the RasterDescription::pdfPageNumber field.
The SDK's RasterDescription structure has a couple of fields to support the Scalable RIP:
ripID
is zero by default (i.e., no Scalable RIP is being run) or greater than zero (i.e., 1 .. N) when multiple farm RIPs are being controlled by a Scalable RIP or RIP farm environment.If you are writing raster backend code, there will be times when you want to step through and debug your code. This can be simplified by setting the Scalable RIP global JSON configuration option FarmRIPDebugWait
to true
. This is because each farm RIP is its own executable with its own address space. Debugging the controlling RIP is of little use when writing raster backends.
This option will cause a farm RIP that has just been launched by the controlling RIP to wait for a debugger to connect to it before continuing. The forced break point is just after the first pass of argument parsing. This allows you to then put further break points on your own raster backend code. So, the workflow is:
FarmRIPDebugWait
to true
in ripfarm_global.json
.-nrips 1
(so you debug just one farm RIP). Although it is fine to debug multiple farm RIPs, this is probably the most useful first pass before looking into concurrency issues.fr001
(for "Farm RIP 1") to make it easier to find.The Scalable RIP raster manager is a component in the Scalable RIP that provides an API for clients to sequence raster output metadata. Raster backends from multiple Farm RIPs in the rip farm may complete pages out of order. Since PDF files are likely to be split amongst multiple farm RIPs, the delivery of rasters for a job are in the order of completion by the farm RIPs. Also, since the Scalable RIP can process multiple jobs simultaneously, it is possible that rasters for a later job be delivered before a job submitted prior to it. For example:
It is also possible that a farm RIP fails to render a page in a job after all other pages have been rendered successfully; you cannot know if a job succeeded completely until all the rasters for a job have been delivered. Remember that page 1 could cause a rendering error after the rasters for pages 2 to N have been delivered for a particular job.
If the client wishes to consume pages in the job order, the Scalable RIP raster manager API can be used to queue the page metadata for the client.
The SDK library provides the support function ripfarm_report_raster() to inform the raster manager API about page output. This function tests whether the Scalable RIP raster manager is enabled. Global Graphics recommends calling this function in all backends you write, in case you wish to enable the Scalable RIP raster manager in future. It should be called:
Note that the raster manager API queues page metadata, not the page's raster data itself. Your application has to determine how raster data should be stored and transported in a RIP farm, and has to ensure that the raster data remains valid until the client consumes it. The ripfarm_report_raster() function may be supplied with a callback function to destroy or release the raster data produced by the raster backend, and a generic data pointer that can be used to identify the raster data. This callback function will be called after a client process calls the raster manager API to indicate that the data is not needed any more. The callback function will not be called on the same thread that called ripfarm_report_raster().
ripfarm_report_raster() has an optional zero-terminated C string parameter called metadata
. The Scalable RIP does not impose any semantics on the meaning of this parameter. It is passed through from your raster backend to a client process that calls the raster manager API to read the page queue. Global Graphics suggests that the metadata represent a JSON string object, but there is nothing in the Scalable RIP that requires this. If the metadata you want to pass to ripfarm_report_raster() is expensive to generate, you may want to make its generation conditional on whether the raster manager is active. The method described in Blank pages and the Scalable RIP raster manager can be used to do this.
The Scalable RIP raster manager must be explicitly enabled in the Scalable RIP configuration JSON if required, by setting the UseRasterManager
parameter to true
. It will be enabled or disabled for the lifetime of the RIP.
The "clrip" application layer provides assistance for debugging raster backends. You may wish to include this in your application while developing your raster output. The debug_page_info() will print the page number, size, and other details for each page output. The debugging is enabled using the /DebugPageInfo
boolean raster parameter. The "clrip" application raster backends call this function in two places: