Skip to main content
Skip table of contents

Custom color post-processing

An Apex custom post process step that operates on non-spot components, i.e. the process colors.

A CCustomColorPostProcessSpec represents a custom post process step that operates on the color (i.e., non-spot components) using an externally supplied Vulkan fragment shader, (optional) textures and
(optional) push constants.

  • The results may be in a different color space than the input.

  • The input color space must match the current color space expected at the point in the post-processing chain where this post process is inserted.

The shader is ultimately invoked over the entire image. However, Apex may break rendering into multiple tiles, in which case the draw operation may occur multiple times.

If the input is a gray color space, then the input will be a single single-channel UNORM image. If the input is RGB, then the input will be a single four-channel UNORM image with the A component ignored. If the input is CMYK, the input will be a single four-channel UNORM image, where R represents Cyan, G represents Magenta, B represents Yellow, and the A channel represents Black. If the input is extended-gamut, then the input will be two four-channel UNORM images, where the first image represents the CMYK components, and the second image represents the extra extended
components, with the first such component in the R channel.

The same is true for the output. If the output is gray, then the output will be a single single-channel image, and so forth.

ℹ️ Please note that all the input and output images are in additive form. That is, the CMYK and extended-gamut components are stored with 0.0 being 100% ink and 1.0
being 0% ink. This mirrors the PDF transparency compositing methods. So take care when interpreting these colors in the shader.

ℹ️ Please also note that if the current render is retaining alpha, then the alpha has not yet been applied to the color values. If alpha is being retained, then the alpha image will be supplied to the shader as the next input after the color inputs.

Push constants may be provided to the shader. However, in addition to any supplied push constants, Apex will push an additional two integer values after these push constants, representing the top-left offset of the tile being rendered. This, in conjunction with the GLSL gl\_FragCoord variable, allows the shader to discover the current coordinate on the final page render, should this be needed.

The size of the push constant buffer is limited, and may differ from GPU to GPU. Vulkan guarantees a minimum of 128 bytes, but remember that Apex will push eight additional bytes for tile coordinates, and therefore the minimum guarantee is 120 bytes. In practice, most GPUs will allow significantly more.
Please see: https://vulkan.gpuinfo.org/displaydevicelimit.php?name=maxPushConstantsSize for supported sizes for current GPUs.

The shader and textures may be created by IApexRenderer::createFragmentShader()and IApexRenderer::uploadImage().

Any textures are provided to the shader after the input images.

For example, consider a custom step where:

  • the input color space is RGB

  • the output color space is extended gamut (e.g. CMYKOG)

  • alpha is being retained

  • two textures are provided

  • a single floating point value for a push constant is provided

The shader would have a structure such as the following:

Click here to see shader code
C
# version 450
// Input images
layout (input\_attachment\_index = 0, binding = 0) uniform subpassInput rgbInput;
layout (input\_attachment\_index = 1, binding = 1) uniform subpassInput alphaInput;
// Textures
layout(binding = 2) uniform sampler2D texture1;
layout(binding = 3) uniform sampler2D texture2;
// Outputs
layout (location = 0) out vec4 resultCmyk; // CMYK portion
layout (location = 1) out vec4 resultOg;   // OG portion
// Push constants
layout (push\_constant) uniform PushConstants
{
    float floatVal;
    int   tileX;
    int   tileY;
} pushConstants;
void main()
{
    // Read the RGB values
    vec3 rgb = subpassLoad(rgbInput).rgb;
    float alpha = subpassLoad(alphaInput).r;

    // Do work here and store the results in resultCmyk and resultOg
}

Code example

Please see this fully-worked example of custom color post-processing that applies a conventional line screen to a rendered page.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.