Created Date: 16 Mar, 2022 15:06
Last Modifed Date: 15 Jun, 2022 09:13

This page applies to Harlequin v13.1r0 and later; both Harlequin Core and Harlequin MultiRIP.

As well as the CalibrationColorModel, a photoink device requires the ink splitting between the light and dark inks to be specified. This is done in the CustomConversions procedures. These convert CMYK and Gray tint values to the photoink space. They must ensure that each of the CMYK and Gray components are only converted to its own inks. (For example, cyan must only transfer ink to the cyan inks; any cross mixing results in an error.

The RGB conversion is ignored because it is never called with the /DeviceCMYK CalibrationColorModel.

In general, photoink splitting uses fairly complex functions that are difficult to write in the PostScript language. It is more appropriate to use C code instead. This can be achieved using a PostScript language device to call out to C code. There is an example photoink PostScript language device in the Harlequin Core Developer’s Guide, which is used in the example below. This example configuration is for a contone, band-interleaved photoink device that splits CMYK to 2, 2, 1, and 3 components, respectively. It illustrates the minimum recommended setpagedevice keys that need to be set for a photoink device. Of these, the ValuesPerComponent, ProcessColorModel, SeparationColorNames, and SeparationOrder are standard keys defined in [RB3]. The remainder are Harlequin extensions (see SeparationDetails in pagedevice keys) and The Harlequin Core Developer’s Guide, Specifying color output capabilities”).

% Workspace for use in photoink splitting, to avoid possible name
% clashes with the photoink devices. It contains some helpers for
% running the CustomConversions.
userdict /photoink_workspace 4 dict put
photoink_workspace begin
  % Photoink device helpers, to minimise VM usage in the
  % CustomConversions procedures.
  /TintDict 1 dict def

  % Puts a tint value into a dict that will be passed to the PS device
  % in a call to setdevparams.
  /set_tint {//TintDict dup /Tint 4 -1 roll put} def

  % Use the PS device to split a tint value into multiple ink values. It
  % uses the /Tint param value from the prior setdevparam.
  % The photoink devices emit binary tokens. This procedure simplifies
  % ensuring that binary tokens will be recognised.
  % colorant-string -> value_1 ... value_N
  % e.g. (%photoink2213%K) -> value_1 value_2 value_3
  /run_splitter {
    currentobjectformat 0 eq {
      % change object format temporarily if it disallows binary scanning
      3 setobjectformat run 0 setobjectformat
    } {
    } ifelse
  } def

  % A dictionary holding input and output values for photoink splitting.
  /d12 12 dict def

  /PageBufferType /LE
  /Halftone false

  /ValuesPerComponent 256
  /Plugin (Example) % default plugin type for DeviceTypes et. al.
  /DeviceType (Photoink2213) % default DeviceType
  /ProcessColorModel /DeviceN
  /CalibrationColorModel /DeviceCMYK % This is a photoink device
  /InterleavingStyle 3 % band interleave

  /SeparationColorNames [
    /PI_Cyan /PI_LightCyan /PI_Magenta /PI_LightMagenta /PI_Yellow
    /PI_Black /PI_LightBlack /PI_ExtraLightBlack
  /SeparationOrder 1 index

  /SeparationDetails <<
    /SeparationStyle 4 % composite
    /SeparationOrdering 5 % fixed order of channels, spots last
    /CompositeColorNames [
      /PI_Cyan /PI_LightCyan /PI_Magenta /PI_LightMagenta /PI_Yellow
      /PI_Black /PI_LightBlack /PI_ExtraLightBlack

    % Device colorant setup.
    /ColorantRender <<
      /PI_Cyan 1 /PI_LightCyan 1 /PI_Magenta 1 /PI_LightMagenta 1 /PI_Yellow 1
      /PI_Black 1 /PI_LightBlack 1 /PI_ExtraLightBlack 1

    /ColorantFamilies [
      % Replace default ColorantFamilies.
        /ColorantFamilyName /DeviceCMYK

        /DeviceTypes [
          << % CMYK 2213 photoink
            /Plugin (Example)
            /DeviceType (Photoink2213)
            /CustomConversions (
              photoink_workspace begin
                    % gray
                    //d12 begin
                    /K_in exch def
                    % K_in -> K_out LightK_out ExtraLightK_out
                    (%photoink2213%) K_in //set_tint exec setdevparams
                    (%photoink2213%K) //run_splitter exec
                    /K_out exch def /LightK_out exch def
                    /ExtraLightK_out exch def

                    % Arrange the output values in the order of the
                    % Colorants array
                    0 0 0 0 0   % Pad the other device colorants
	                K_out LightK_out ExtraLightK_out

                    % c lc m lm y k lk elk end

                  {null} % rgb conversion will cause an error, but will
                         % never be used. Photoink color management will
                         % avoid using it.

                    % c m y k
                    //d12 begin
                    /K_in exch def
                    /Y_in exch def
                    /M_in exch def
                    /C_in exch def

                    % C_in -> LightC_out C_out
                    (%photoink2213%) C_in //set_tint exec setdevparams
                    (%photoink2213%C) //run_splitter exec
                    /C_out exch def /LightC_out exch def
                    % M_in -> LightM_out M_out
                    (%photoink2213%) M_in //set_tint exec setdevparams
                    (%photoink2213%M) //run_splitter exec
                    /M_out exch def /LightM_out exch def
                    % Y_in -> Y_out
                    (%photoink2213%) Y_in //set_tint exec setdevparams
                    (%photoink2213%Y) //run_splitter exec
                    /Y_out exch def
                    % K_in -> ExtraLightK_out LightK_out K_out
                   (%photoink2213%) K_in //set_tint exec setdevparams
                   (%photoink2213%K) //run_splitter exec
                    /K_out exch def /LightK_out exch def
                    /ExtraLightK_out exch def

                    % Arrange the output values in the order of the
                    % Colorants array
                    C_out LightC_out
                    M_out LightM_out
                    K_out LightK_out ExtraLightK_out

                    % c lc m lm y k lk elk
                } cvlit
              end   % photoink_workspace
            )   % custom conversion string

            /Colorants [
              % Arrange the colorant list in the order required by the device
              << /sRGB [0.0 1.0 1.0] /Presence 2 /ColorantType 1 /Names [ (PI_Cyan) ] >>
              << /sRGB [0.4 1.0 1.0] /Presence 2 /ColorantType 1 /Names [ (PI_LightCyan) ] >>
              << /sRGB [1.0 0.0 1.0] /Presence 2 /ColorantType 1 /Names [ (PI_Magenta) ] >>
              << /sRGB [1.0 0.4 1.0] /Presence 2 /ColorantType 1 /Names [ (PI_LightMagenta) ] >>
              << /sRGB [1.0 1.0 0.0] /Presence 2 /ColorantType 1 /Names [ (PI_Yellow)] >>
              << /sRGB [0.0 0.0 0.0] /Presence 2 /ColorantType 2 /Names [ (PI_Black) ] >>
              << /sRGB [0.4 0.4 0.4] /Presence 2 /ColorantType 1 /Names [ (PI_LightBlack) ] >>
              << /sRGB [0.6 0.6 0.6] /Presence 2 /ColorantType 1 /Names [ (PI_ExtraLightBlack) ] >>

          % Other photoink device types should go here
          % ...
        ]   % DeviceTypes
    ]   % ColorantFamilies
  >>    % SeparationDetails
>> setpagedevice

The ColorantFamilies defines the capabilities of the colorants for the Photoink2213 DeviceType. If this device is capable of being used with different photoink splitting (for example, if the black is split into only two components), this should be represented by additional colorant family dictionaries within the DeviceTypes array.

The CustomConversions procedures in the example use boilerplate code that can be largely reused for other devices. The main change required for production devices is the order of colorants and the number of inks for each CMYK component. Most of the work in a successful photoink development is in writing the C code for implementing the splitting. That is an art which is left to customers.

It is common practice to supply a ColorantFamilies array containing all available families (just once in startup code). Thereafter, switching between families is done by calling setpagedevice with the Plugin and DeviceType matching the new selection.

The names used for the device colorants in the example are all preceded by the PI_.

There is only one restriction on the names; they cannot be standard process colorant names (for example, /Cyan).