Harlequin RIP SDK

A screening module for multi-level dispersed screening. More...

#include "std.h"
#include "htm8ml.h"
#include "hqspin.h"
#include <string.h>

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_apihtm8ml_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 uint8g_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...
 

Detailed Description

A screening module for multi-level dispersed screening.

Macro Definition Documentation

◆ LUT_INPUT_SIZE

#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.

◆ ML8_LISTADD

#define ML8_LISTADD (   p,
  head 
)
Value:
MACRO_START \
if (head) (head)->prev = (p); \
(p)->next = (head); \
(p)->prev = NULL; \
(head) = (p); \
MACRO_END
#define NULL
Definition of NULL pointer.
Definition: hqtypes.h:37

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.

◆ RIPAPI_ALLOC

#define RIPAPI_ALLOC (   memapi_,
  size 
)     (memapi_)->implementation->alloc((memapi_), size)

Allocate a block of memory using the API offered by the RIP.

Note
The RIP does not zero memory allocated via this API.
Parameters
[in]memapi_Pointer to the memory API instance.
[in]sizeThe number of bytes required.
Returns
Pointer to the allocated block, or NULL on error.

◆ RIPAPI_FREE

#define RIPAPI_FREE (   memapi_,
  ptr 
)
Value:
MEMAPI_ASSERTS(memapi_) ; \
(memapi_)->implementation->free((memapi_), ptr) ; \
MACRO_END
#define MEMAPI_ASSERTS(memapi_)
Ensure the APIs we use are hooked up.
Definition: htm8ml.c:2623

Free memory which was allocated via API offered by the RIP.

Parameters
[in]memapi_Pointer to the memory API instance.
[in]ptrThe pointer to the memory block.

Typedef Documentation

◆ 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.

◆ 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.

Function Documentation

◆ buildSolution()

static void buildSolution ( int32  levels,
multilevel_lookup_solution soln 
)
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.

Parameters
[in]levelsThe number of levels to solve for.
[in,out]solnPointer to the structure to hold the solution for that number of levels.

◆ doneWithSolution()

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.

Parameters
[in]ml8implPointer to the implementation subclass.
[in]solnPointer to the solution no longer needed.

◆ ml8SupportedDestinationBitDepth()

HqBool ml8SupportedDestinationBitDepth ( int  depth)

Whether we support the destination raster bit depth.

Parameters
[in]depthThe final output raster depth.
Return values
TRUEif the bit depth is supported
FALSEif the bit depth is not supported.

◆ prepareSolution()

static sw_htm_result prepareSolution ( ml8_htimplementation ml8impl,
int32  levels,
multilevel_lookup_solution **  ppSoln 
)
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.

Parameters
[in]ml8implPointer to the implementation subclass.
[in]levelsThe number of levels to solve for.
[out]ppSolnWhere to store the pointer to the solution.
Returns
SW_HTM_SUCCESS, or one of the sw_htm_error constants.

Variable Documentation

◆ black_table

uint8 black_table[]
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.

◆ cyan_table

uint8 cyan_table[]
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.

◆ g_ml_filter_table_sizes

int32 g_ml_filter_table_sizes[4] = { 64, 68, 72, 76 }
static

Subscriptable table of threshold table sizes.

Each entry is the size of both the horizontal and vertical dimension of the appropriate table.

◆ htmApi

ml8_htimplementation htmApi
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.

◆ magenta_table

uint8 magenta_table[]
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.

◆ yellow_table

uint8 yellow_table[]
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.