A screening module for multi-level dispersed screening. More...
Data Structures | |
struct | multilevel_lookup_solution |
Distribution solution for a specific number of levels. More... | |
struct | ml8_htinstance |
This structure holds our halftone instance information. More... | |
struct | ml8_htimplementation |
This structure holds our halftone implementation information. More... | |
Macros | |
#define | ML8_LISTADD(p, head) |
Add an element to one of our lists. More... | |
#define | ML8_LISTREMOVE(p, head) |
Remove an element from one of our lists. | |
#define | LUT_INPUT_SIZE 256 |
Size of the input value dimension of the solution lookup table. More... | |
#define | LUT_INPUT_SHIFT 8 |
The binary log of LUT_INPUT_SIZE. | |
#define | MEMAPI_ASSERTS(memapi_) |
Ensure the APIs we use are hooked up. | |
#define | RIPAPI_ALLOC(memapi_, size) (memapi_)->implementation->alloc((memapi_), size) |
Allocate a block of memory using the API offered by the RIP. More... | |
#define | RIPAPI_FREE(memapi_, ptr) |
Free memory which was allocated via API offered by the RIP. More... | |
Typedefs | |
typedef struct multilevel_lookup_solution | multilevel_lookup_solution |
Distribution solution for a specific number of levels. More... | |
typedef struct ml8_htinstance | ml8_htinstance |
This structure holds our halftone instance information. More... | |
Functions | |
HqBool | ml8SupportedDestinationBitDepth (int depth) |
Whether we support the destination raster bit depth. More... | |
static HqBool | ml8Init (sw_htm_api *implementation, const sw_htm_init_params *params) |
Implementation of sw_htm_api::init(). More... | |
static sw_htm_result | ml8HalftoneSelect (sw_htm_instance *instance, const sw_htm_select_info *info, sw_htm_instance **matches) |
Implementation of sw_htm_api::HalftoneSelect(). More... | |
static void | ml8HalftoneRelease (sw_htm_instance *instance) |
Implementation of sw_htm_api::HalftoneRelease(). More... | |
static sw_htm_result | ml8RenderInit (sw_htm_api *implementation, const sw_htm_render_info *render_info) |
Implementation of sw_htm_api::RenderInitiation(). More... | |
static HqBool | ml8DoHalftone (sw_htm_instance *instance, const sw_htm_dohalftone_request *request) |
Implementation of sw_htm_api::DoHalftone(). More... | |
static void | ml8AbortHalftone (sw_htm_instance *instance, const sw_htm_dohalftone_request *request) |
Implementation of sw_htm_api::AbortHalftone(). More... | |
static void | buildSolution (int32 levels, multilevel_lookup_solution *soln) |
Calculate the lookup solution for a given number of levels. More... | |
static sw_htm_result | prepareSolution (ml8_htimplementation *ml8impl, int32 levels, multilevel_lookup_solution **ppSoln) |
Prepare a solution for the given number of levels. More... | |
void | doneWithSolution (ml8_htimplementation *ml8impl, multilevel_lookup_solution *soln) |
The given reference to a solution is no longer needed. More... | |
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. More... | |
Variables | |
static uint8 | cyan_table [] |
Threshold tables. More... | |
static uint8 | magenta_table [] |
Threshold tables. More... | |
static uint8 | yellow_table [] |
Threshold tables. More... | |
static uint8 | black_table [] |
Threshold tables. More... | |
static uint8 * | g_ml_filter_tables [4] |
Subscriptable table of threshold table pointers. | |
static int32 | g_ml_filter_table_sizes [4] = { 64, 68, 72, 76 } |
Subscriptable table of threshold table sizes. More... | |
static ml8_htimplementation | htmApi |
The sw_htm_api used to register the module with the RIP is the superclass of the singleton ml8_htimplementation. More... | |
A screening module for multi-level dispersed screening.
#define LUT_INPUT_SIZE 256 |
Size of the input value dimension of the solution lookup table.
Note: A production-quality 16-bit screen would have a lookup table larger than 256 items in the first subscript.
#define ML8_LISTADD | ( | p, | |
head | |||
) |
Add an element to one of our lists.
This module uses lists with elements having next
and prev
pointers. The next
pointer is NULL
at the tail of the list. The prev
pointer is NULL
at the head of the list. A single static pointer points to the head of the list, and is NULL
when the list is empty. We only add to the front of the list using the head
pointer.
#define RIPAPI_ALLOC | ( | memapi_, | |
size | |||
) | (memapi_)->implementation->alloc((memapi_), size) |
Allocate a block of memory using the API offered by the RIP.
[in] | memapi_ | Pointer to the memory API instance. |
[in] | size | The number of bytes required. |
#define RIPAPI_FREE | ( | memapi_, | |
ptr | |||
) |
Free memory which was allocated via API offered by the RIP.
[in] | memapi_ | Pointer to the memory API instance. |
[in] | ptr | The pointer to the memory block. |
typedef struct ml8_htinstance ml8_htinstance |
This structure holds our halftone instance information.
This structure is a sub-class of sw_htm_instance.
One of these structures will exist, in our internal list, for each screen which has been selected by the RIP. That's one for each combination of levels-solution, screen-index and whether or not the inverse is required.
typedef struct multilevel_lookup_solution multilevel_lookup_solution |
Distribution solution for a specific number of levels.
The original implementation of this algorithm used a static pre-calculated distribution table, which only allowed for one single number of tone levels to be in use at any one time. Instead, we use a cache list so that we can co-exist two or more sets of screens using different numbers of tone levels.
This structure holds the distribution solution we have calculated for a specific number of levels.
|
static |
Calculate the lookup solution for a given number of levels.
This code calculates the contents of the distribution array for multi-level screening. This determines what gray level we use for any particular pixel. Since on average, over an area, we want the requested gray level to be the same as the resultant gray level, the contents of each array should add up to 256 times the gray level. However, the gray levels we have available are only a few discrete ones (say, 8 at 3 bits, including 0 and 255, and only therefore 7 intervals). So we need to vary the proportions of each gray level such that this sum is achieved. In principle, this could be all the next lower gray level except for enough of the next higher one to compensate for the remainder when the next lower gray level is subtracted from the required level.
In practice this causes nasty artifacts when remainder is zero, where we transition from a noisy area containing more than one level to a smooth area of one level and back again. Instead we maintain three levels (dropping occasionally to two, or very close). The centre of each array contains the next lower level (index m), the left part the next lower still (m-1) and the right part the next higher (m+1). As the gray level increases we bring in more of the right value and fewer of the left.
This is a bit like sliding a window leftwards along the array containing the centre value; when it drops off the bottom, we carry the amount we lost back to the top and the window switches places. There are special cases at beginning and end where there is no next lower still or next higher. Here we let the boundary between levels increase up to some threshold and then start bringing in a further level. The threshold determines the ratio of the next lower value to the other two all the way through, and the remainder is dealt with solely by varying the proportion of highest and lowest levels.
[in] | levels | The number of levels to solve for. |
[in,out] | soln | Pointer to the structure to hold the solution for that number of levels. |
void doneWithSolution | ( | ml8_htimplementation * | ml8impl, |
multilevel_lookup_solution * | soln | ||
) |
The given reference to a solution is no longer needed.
Decrement the solution's reference count. If this is the last reference, the solution can be freed.
[in] | ml8impl | Pointer to the implementation subclass. |
[in] | soln | Pointer to the solution no longer needed. |
HqBool ml8SupportedDestinationBitDepth | ( | int | depth | ) |
Whether we support the destination raster bit depth.
[in] | depth | The final output raster depth. |
TRUE | if the bit depth is supported |
FALSE | if the bit depth is not supported. |
|
static |
Prepare a solution for the given number of levels.
First see if a solution for that number of levels is already cached. If not, allocate and build the solution and add it to the cache.
[in] | ml8impl | Pointer to the implementation subclass. |
[in] | levels | The number of levels to solve for. |
[out] | ppSoln | Where to store the pointer to the solution. |
|
static |
Threshold tables.
These can be thought of as very small, square, HDS cells (Harlequin Dispersed Screening).
However, they aren't used as a simple thresholding screen, but as a distribution table, such that we choose a contone level above or below the required level according to the value in the table aligned on the raster grid.
It is a requirement of this algorithm that the tables are square, i.e., that they have the same horizontal and vertical size.
Note that although these tables are referred to herein with names such as "cyan_table" and "magenta_table", they are really just four different tables. The mapping of which table is used to screen which colorant is the responsibility of the PDL, e.g., via sethalftone
.
|
static |
Threshold tables.
These can be thought of as very small, square, HDS cells (Harlequin Dispersed Screening).
However, they aren't used as a simple thresholding screen, but as a distribution table, such that we choose a contone level above or below the required level according to the value in the table aligned on the raster grid.
It is a requirement of this algorithm that the tables are square, i.e., that they have the same horizontal and vertical size.
Note that although these tables are referred to herein with names such as "cyan_table" and "magenta_table", they are really just four different tables. The mapping of which table is used to screen which colorant is the responsibility of the PDL, e.g., via sethalftone
.
|
static |
Subscriptable table of threshold table sizes.
Each entry is the size of both the horizontal and vertical dimension of the appropriate table.
|
static |
The sw_htm_api used to register the module with the RIP is the superclass of the singleton ml8_htimplementation.
It is initialized in htm8ml_getInstance(), later.
This is also how to access RIP APIs such as sw_memory_api.
|
static |
Threshold tables.
These can be thought of as very small, square, HDS cells (Harlequin Dispersed Screening).
However, they aren't used as a simple thresholding screen, but as a distribution table, such that we choose a contone level above or below the required level according to the value in the table aligned on the raster grid.
It is a requirement of this algorithm that the tables are square, i.e., that they have the same horizontal and vertical size.
Note that although these tables are referred to herein with names such as "cyan_table" and "magenta_table", they are really just four different tables. The mapping of which table is used to screen which colorant is the responsibility of the PDL, e.g., via sethalftone
.
|
static |
Threshold tables.
These can be thought of as very small, square, HDS cells (Harlequin Dispersed Screening).
However, they aren't used as a simple thresholding screen, but as a distribution table, such that we choose a contone level above or below the required level according to the value in the table aligned on the raster grid.
It is a requirement of this algorithm that the tables are square, i.e., that they have the same horizontal and vertical size.
Note that although these tables are referred to herein with names such as "cyan_table" and "magenta_table", they are really just four different tables. The mapping of which table is used to screen which colorant is the responsibility of the PDL, e.g., via sethalftone
.