The htm8ml example of the modular screening API implements a multi-level screening technique which produces a configurable number of levels, and where the transition between levels is dispersed using a stochastic screen cell. More...
Files | |
file | htm8ml.h |
HTM Interface to a simple example screening module which implements a set of multi-level dispersed screens. | |
file | htm8ml.c |
A screening module for multi-level dispersed screening. | |
The htm8ml example of the modular screening API implements a multi-level screening technique which produces a configurable number of levels, and where the transition between levels is dispersed using a stochastic screen cell.
Based on the principle that it can theoretically be configured to produce any desired number of different output pixel values ('levels'), between 2 and 255, it currently supports destination raster depths of 1, 2, 4 and 8 bits per pixel (although not all RIP implementations support screened output to all those bit depths).
The destination bit depth is determined by the RIP, of course, from the /ValuesPerComponent
page device key, whereas the desired number of 'levels' is configured via the module's halftone dictionary using the /Levels
key.
It is the responsibility of the creator of the relevant halftone dictionary to ensure that the number of 'levels' being produced is appropriate for the number of bits per pixel in the output raster.
Beware, though, that although the desired number of levels will be distributed as smoothly as possible across the output bit depth, some combinations will exhibit distinct non-linearity across the values. For example, you can't really distribute 10 levels evenly across the 16 possible pixel values of 4-bit per pixel output.
It's relatively easy, though, to use code in the RIP back end to re-distribute the pixel values generated by the halftone module as you see fit, for example using a simple look up table.
Different final device bit depths could, of course, be obtained by configuring the RIP to use a larger number of bits per pixel, and then using a similar look-up technique in the RIP back end to re-map the pixel values to ones suitable for fewer bits. For example producing 8 levels with a 4-bit destination raster converted to 3 bits per pixel in the back end before transmission to the device.
(However, note that RIPs which do not support 8-bit halftoned destination raster are consequently limited to a maximum of 4-bits per pixel final output depth.)
Internally, the module uses a form of dispersed stochastic screen tile, similar to Harlequin Dispersed Screening, to distribute the individual pixel values across the area being rendered.
It has four such tiles, thus allowing a basic set of four separate 'separations' to be screened.
Which tile to use is determined by the /Screen
key in the halftone dictionary - a number between 0 and 3.
Furthermore the tiles are constructed in such a way that they can also be processed in the 'inverse' order enabling different colorants to 'share' the same screen without overlapping as such. This 'inverse' option is very useful, for example, when utilising more than one shade of ink, such as Light Cyan and Dark Cyan - the light ink can use one tile while the dark screen uses its inverse.
The use of the inverse screen is triggered by setting the /Inverse
key of the halftone dictionary to true.
An example of a valid halftone dictionary for this module might be:
<< /HalftoneType 100 /HalftoneModule /htm8ml /Screen 0 /Levels 4 >>
which will generate 4 levels (suitable for 2 bits per pixel output) using internal tile number 0 to distribute the pixel values.
A pair of colorants might be declared sharing a tile like this:
/LightCyan << /HalftoneType 100 /HalftoneModule /htm8ml /Screen 0 /Levels 4 >> /DarkCyan << /HalftoneType 100 /HalftoneModule /htm8ml /Screen 0 /Levels 4 /Inverse true >>
You can see some complete examples of declaring halftone dictionaries for this module in the RIP's data directory, in SW/Sys/ExtraStart/HtmEg
.
To demonstrate the htm8ml screen in action, you can use the configuration in SW/TestConfig/HTM/CMYKCompHtm8mlSeps300dpi3bit
with the "clrip" application. This will produce 4-bit-per-pixel output rasters screened using just 8 different levels (values) for each pixel.
This example module is registered by calling SwRegisterHTM() with the singleton API instance returned by htm8ml_getInstance(). The module implements the modular screening API methods ml8Init(), ml8HalftoneSelect(), ml8HalftoneRelease(), ml8RenderInit(), ml8DoHalftone(), and ml8AbortHalftone().
sw_htm_api* htm8ml_getInstance | ( | void | ) |
Return the singleton instance of the sw_htm_api object containing details of the example multi-level screening module.
If compiled normally, the "clrip" application layer registers this module during RIP startup. Halftone module examples may be excluded from "clrip" by building with NO_HTMEG
defined.
|
static |
Implementation of sw_htm_api::AbortHalftone().
The RIP calls ml8AbortHalftone() when it wants the module to stop rendering an outstanding request issued by ml8DoHalftone() with the same arguments.
The module must stop writing to its output buffers and then invoke sw_htm_dohalftone_request::DoneHalftone() before returning (it is permissible to invoke it from another thread). Because the calls can't be synchronized, it may happen that the module has already called sw_htm_dohalftone_request::DoneHalftone() between the RIP deciding to abort and actually invoking AbortHalftone(). This is acceptable, but the module must be so constructed that any such sw_htm_dohalftone_request::DoneHalftone() has, in fact, returned before AbortHalftone() returns. The RIP will check if the request has, in fact, terminated, and it is an error if it hasn't.
[in] | instance | Pointer to a halftone instance selected by HalftoneSelect(). |
[in] | request | Pointer to a structure holding details of the RIP's halftone request. |
|
static |
Implementation of sw_htm_api::DoHalftone().
This is the most important function in the module.
The RIP calls ml8DoHalftone() when it wants the module to render a halftone instance into a channel within the RIP's band buffers.
In the case of this example, the halftoning is so simple that even if the RIP were capable of asynchronous calls, we would still opt to complete ours synchronously.
[in] | instance | Pointer to a halftone instance selected by HalftoneSelect(). |
[in] | request | Pointer to a structure holding details of the RIP's halftone request. |
FALSE | The module is unable to accept the request. In this case, the module must not touch any arguments passed to it, and the RIP will deem this an unrecoverable failure. |
TRUE | The module accepts the request and will call sw_htm_dohalftone_request::DoneHalftone() when done. The success or failure of the overall request is indicated by the result parameter of sw_htm_dohalftone_request::DoneHalftone(). |
The module must not block on something that depends on another DoHalftone() invocation being made. Even if sw_htm_render_info::max_render_threads > 1, there's no guarantee that another invocation can be made concurrently.
The module must call sw_htm_dohalftone_request::DoneHalftone() using exactly the same request pointer passed in to it.
|
static |
Implementation of sw_htm_api::HalftoneRelease().
ml8HalftoneRelease() will be called once for each previously successful ml8HalftoneSelect() when the RIP no longer needs the halftone instance.
In this example, our function doneWithSolution() handles everything that ml8HalftoneRelease() requires, so all that's needed is to call that.
HalftoneRelease() will be called once for each previously successful HalftoneSelect(), with the instance pointer that is not required. The implementation should clean up any resources associated with the instance.
[in] | instance | The halftone instance value originally constructed by HalftoneSelect(). |
|
static |
Implementation of sw_htm_api::HalftoneSelect().
ml8HalftoneSelect() is called when the page description language (PDL) does the equivalent of a PostScript sethalftone
.
The RIP calls us individually for each halftone needed, so in the case of multi-colorants, such as a PostScript type 5 halftone dictionary, the RIP will call us for each colorant sub-dictionary therein.
We only have to worry, therefore, about a single halftone instance in any one call.
The key names this module understands from the halftone dictionary are:
false
.This example is relatively simple, so after validating our parameters, we call our prepareSolution() function to calculate the distribution solution for the requested number of levels and initialise one of our ml8_htinstance structures for the combination of levels, screen and inverse-setting.
[in,out] | instance | An incomplete instance of the sw_htm_instance structure to complete. The RIP will allocate a structure of the size presented in the implementation's sw_htm_api::info.instance_size field, fill in the implementation and callback API instance pointers, and then pass it to this routine. The HalftoneSelect() method is expected to fill in the remaining fields. The implementation may sub-class the instance to allocate private workspace by initialising the sw_htm_api::info.instance_size larger than the size of the sw_htm_instance structure, then downcasting the instance pointer in method calls. |
[in] | info | Halftone selection information from the RIP. This contains things like the halftone phase and a pointer to an information structure describing the destination raster and colorants etc. It also contains a data access API, a datum representing the colorant name for which this halftone is being selected and a datum representing the halftone dictionary. Any data accessed through this pointer MUST be copied if the halftone instance wished to refer to it after the HalftoneSelect() method has returned. |
[out] | matches | If the halftone module currently has an instance selected that maps onto the same screen, it should store the existing instance in this pointer and return SW_HTM_SUCCESS. In this case, the instance under construction will be destroyed immediately, and there will be no call to HalftoneRelease(). This will ensure that equivalent screen definitions share the same DoHalftone() calls, and will improve rendering efficiency. It is an error to store the instance under construction through this pointer. |
|
static |
Implementation of sw_htm_api::init().
ml8Init() is called once when the RIP boots up, before all other methods in this interface. It is used here to initialize implementation class-specific data.
This method may be used to initialise any implementation-specific data. This method is optional.
implementation | The registered modular halftone implementation to be initialised. | |
[in] | params | A structure containing callback APIs and parameters valid for the lifetime of the module. Any parameters that the implementation needs access to should be copied out of this structure into private storage for the registered implementation. |
TRUE | Success, indicating that the implementation is fully initialised. |
FALSE | Failure to initialise the implementation. If this is returned, the implementation will not be finalised. |
|
static |
Implementation of sw_htm_api::RenderInitiation().
The RIP calls ml8RenderInit() when it prepares to render a page.
This primitive example won't benefit from more memory, so we don't really have much to do in this function. We just check that the source (contone) and destination (halftone) raster bit depths are appropriate, and let the RIP know our rendering needs.
RenderInitiation() is a class function. It will be called once for each halftone module that may have halftones used on a page.
In the case of color-separated output, RenderInitiation() takes place once, before the RIP renders all the separations of a page.
Note that when the RenderInitiation() is for a partial paint, very little memory will be available, so any mandatory buffers should be preallocated during HalftoneSelect().
This method is optional.
[in] | implementation | A pointer to the implementation registered with the RIP. |
[in] | render_info | Pointer to a structure containing general information about the upcoming render as a whole. |