Technical Article

Uncolored PDF Patterns: Where Does the Hatch Color Come From?

A hatch in a PDF has the expected angle and spacing, but its color is wrong. The tint operands are interpreted through the pattern's base color space. PDFlibPas resolves that space before decoding the tint, whether it is a device space, a named resource or an array

Where does an uncolored pattern get its color?

A tiling pattern repeats a small cell over the area being painted. A colored pattern supplies its own color instructions; an uncolored one, identified by /PaintType 2 in its pattern dictionary, obtains the color from the graphics state set by the caller. One hatch cell can consequently be reused in several colors without duplicating its geometry. That arrangement changes where to look when a red hatch appears on the page. The pattern stream might contain only the lines that make up the hatch, while the red tint was selected earlier in the page's content stream. The pattern dictionary, color-space resource and painting operation each contribute part of the result

Read cs and scn together

For the following fragment, assume the active resources define /HatchCS as [/Pattern /DeviceRGB] and /Hatch as an uncolored tiling pattern. The page selects the color space, supplies a tint and fills a rectangle

/HatchCS cs
1 0 0 /Hatch scn
72 500 200 80 re
f

The lowercase cs operator selects the nonstroking color space. The scn that follows supplies three DeviceRGB components and the pattern name; the subsequent fill uses both the tint and the repeated pattern cell. Those resource entries and the pattern dictionary must exist for the fragment to form part of a working page. An outline uses the corresponding stroking operators and its own graphics state, so a hatch used for a stroke must be traced through that state rather than only through the fill color. The capitalization of the operators tells us which state the content stream changes

Why do three operands not prove RGB?

The operands do not identify the base space by themselves. A resource name can point to a device space or to an array defining an ICC-based, Indexed, Lab, Separation or DeviceN space; that definition determines the expected components and their interpretation. Separation and DeviceN color spaces use a tint transform to map ink values to an alternate space. An ICC-based space uses its profile for the color interpretation. Three operands might fit more than one definition, so counting them cannot reveal which one the page selected. Follow the resource reference to the actual color-space object before you decide how to interpret the tint values, and keep the containing stream in view while resolving a name

DeviceRGB and DeviceCMYK offer a straightforward contrast. The earlier RGB operation supplies three components; a DeviceCMYK base uses four. The hatch cell itself can remain the same, because its geometry is independent of the caller's tint. If the content stream says only /HatchCS cs, the resource dictionary supplies the missing explanation of which components the following scn expects. An ICC-based array adds its profile and component count; a Separation definition adds its tint transform and alternate space. These objects can affect the final color even when the repeated lines and their spacing have not changed. A stream excerpt that omits its active resources therefore leaves an important part of the color decision out of view. For a named base, keep following the reference until the resource definition is available, rather than assigning a meaning to the name based on its spelling. Two documents can use the same resource name for different definitions, so the dictionary belonging to the active content stream is the one that determines how its operands are interpreted

PDFlibPas resolves the selected base color space before routing the tint through color decoding, while the selected pattern provides the repeated geometry. If you see incorrect hatch spacing, start with the pattern cell and matrix. If the lines are in the right places but have the wrong tint, the base space, supplied components and color conversion are better places to begin

Render the hatch from Delphi

The first Delphi routine renders page 1 of an existing PDF to PNG. Start with a rectangle filled by a simple uncolored hatch and a known DeviceRGB base; at a fixed output resolution the resulting image provides a reference for the geometry and tint before introducing a more complex base-space definition

uses
  SysUtils, PDFlibrary;

procedure RenderPatternSample(const PdfFile, ImageFile: string);
var
  Pdf: TPDFlib;
begin
  Pdf := TPDFlib.Create;
  try
    if Pdf.LoadFromFile(PdfFile, '') <> 1 then
      raise Exception.Create('Cannot open the PDF');
    if Pdf.RenderPageToFile(144, 1, PDF_RENDER_PNG, ImageFile) <> 1 then
      raise Exception.Create('Cannot render page 1');
  finally
    Pdf.Free;
  end;
end;

The second routine prints the selected page's content stream. Look for the relevant cs and scn operations and record their operands, then resolve their names in the active resource dictionary. A named color space is defined by its resource object, so the printed stream is only one part of the investigation

procedure PrintPatternOperators(const PdfFile: string);
var
  Pdf: TPDFlib;
begin
  Pdf := TPDFlib.Create;
  try
    if Pdf.LoadFromFile(PdfFile, '') <> 1 then
      raise Exception.Create('Cannot open the PDF');
    if Pdf.SelectPage(1) <> 1 then
      raise Exception.Create('Cannot select page 1');
    Writeln(string(Pdf.GetPageContentToString));
  finally
    Pdf.Free;
  end;
end;

Before you judge the rendered colors, check that the two pages use the same hatch geometry and matrix. Otherwise a difference in spacing or placement can obscure the effect of the base-space selection. A useful control keeps the repeated cell and its matrix unchanged while changing only the base-space definition and tint operands. Once the geometry is established, follow the selected resource name to its definition and interpret the supplied components in that space before drawing conclusions from the output color

Follow the resource chain when the color is wrong

Work backward from the operation that paints the hatch. A filled path uses the nonstroking state, while an outline uses the stroking state; locate the corresponding color-space selection and resolve its name where that stream executes. If the base is another named resource, follow it to the actual definition and read the supplied tint components against that definition. Next look at the pattern dictionary and cell. A wrong angle points toward the geometry or matrix; correctly spaced lines in the wrong color point toward the base space or color conversion. Forms deserve special care: a page and a Form XObject may both use a resource called /HatchCS without naming the same object. Record the containing stream with the resource name; a page-level lookup alone can point you to the wrong resource

A comparison that catches the common shortcut

Use a few diagonal lines in a rectangular pattern cell over a solid background. The simple geometry makes a tint change visible without hiding a spacing error in a dense design. Reuse that cell with a DeviceRGB base and with a named or array-defined base whose expected tint is known, and include both a filled rectangle and a stroked outline—the two graphics states need their own checks. For spot-color work, follow the tint transform and alternate-space definition through the intended proofing workflow. A monitor can show the hatch while giving only a display approximation of the intended ink. We prefer to establish the repeated geometry with a simple base space first, then introduce the profile or tint transform; that leaves fewer possible causes when the color changes

A reduced page needs the pattern resources and any color profile that define its tint. If you copy only the visible path, you can leave out precisely the object that explains the color. For surrounding operations, see vector graphics and shading and document color-space conversion. The rendering routines above use PDF Library for Delphi