Technical Article

Why a PDF Zero-Width Line Still Shows Up

A fine PDF rule grows unexpectedly thick when the page is scaled. The content stream specifies 0 w, meaning a device hairline rather than a one-unit stroke. PDFlibPas renders that special width at device-pixel thickness; positive widths remain part of the page geometry and follow its transform

Even two strokes with the same width can look unlike each other on screen. A horizontal line may align with one row of pixels, while antialiasing spreads a diagonal across several neighboring pixels. Resolution changes the physical size of a raster pixel too: at 72 pixels per inch it spans approximately 0.353 millimeters, and at 144 pixels per inch approximately 0.176 millimeters. Those numbers describe pixels at the stated resolution. Printer scaling and halftoning affect the mark on paper, so a print workflow has to be judged with its own output settings. Before changing the path, look at how it was rendered and whether an additional scale was applied after the PDF page was laid out

What does the w operator change?

The PDF graphics state carries the current line width, set by w. Later stroke operations use that setting until another width is selected or a saved state is restored. For a positive width, the value is in user space and the current transformation matrix determines how it reaches the output device

q
0 w
72 720 m
300 720 l
S
Q

In the stream, q saves the state; 0 w selects a hairline; m and l establish the path; and S strokes it. The final Q restores the earlier state. ISO 32000-2 section 8.4.3.2 describes the special meaning of width zero. The path's centerline still follows the coordinates given to m and l, while the stroke determines the region painted around it. That is why a rule can be in exactly the right position yet look too heavy. Caps and joins contribute to the visible outline: a square cap extends beyond an endpoint, for example. Hold them steady when studying the width. For a production drawing that specifies a physical line weight, choose a positive width in the appropriate page units; a device hairline serves a different purpose

Why is one user unit not one pixel?

The page matrix changes a positive width along with the rest of the drawing. Zero is the exception: PDFlibPas maps it to a device-pixel pen. Replacing zero with one user-space unit before applying the matrix would make the resulting width scale with the page, turning a fine mark into a thick rule at a larger output size. The opposite case is easy to miss too. A technical drawing may use a large numeric width under a small scale and produce a perfectly ordinary line on the page. An arbitrary cutoff on the untransformed number discards that context. Read the width and transformation together when you diagnose a stroke, and keep both zero and a known positive width in a rendering test. They exercise two different calculations

Render two strokes at fixed settings

The first Delphi routine renders page 1 of an existing PDF to PNG. For a controlled comparison, use a page containing two parallel lines, one with width zero and one with a known positive width, and render the same page at both 72 and 144 DPI. Keep its page box and rotation unchanged while you change the resolution

uses
  SysUtils, PDFlibrary;

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

The next routine creates the two-line page. PDFlibPas uses its current measurement units for the positive width, while zero selects the device hairline. We generated a PDF with this routine and read its decoded content stream: the first stroke carried 0 w, and the second carried 0.5 w. Pass the saved file to the rendering routine above at each resolution, using distinct output names

procedure CreateLineSample(const FileName: string);
var
  Pdf: TPDFlib;
begin
  Pdf := TPDFlib.Create;
  try
    Pdf.SetLineWidth(0);
    Pdf.DrawLine(20, 30, 160, 30);
    Pdf.SetLineWidth(0.5);
    Pdf.DrawLine(20, 40, 160, 40);
    if Pdf.SaveToFile(FileName) <> 1 then
      raise Exception.Create('Cannot save sample PDF');
  finally
    Pdf.Free;
  end;
end;

Look at the two strokes at their native bitmap sizes before you judge thickness or resize either image. Resizing one PNG afterward is a different operation from asking the PDF renderer to produce another image at a higher resolution. At a higher render resolution, the positive-width line follows the page-to-device scaling, whereas the zero-width case requests the device hairline. Keep the path, width settings and page transform with the output so that a change in line position is not confused with a change in thickness

Where to look when the rule is still too thick

If you still see an excessively thick rule, begin at its stroke operation and work backward through the active graphics state. Find the applicable w, any transforms, and the q/Q nesting. A restore can bring back a line width selected much earlier in the stream, so the operator immediately before the path is not necessarily the whole story. Rendering settings come next. Antialiasing can color adjacent pixels even when the underlying stroke is a hairline; a diagonal naturally touches a different pixel pattern from a horizontal rule. We would establish the path and its transformed geometry first, then examine the edge pixels, rather than treating every gray antialiasing pixel as another unit of stroke width

Print scaling can add a further transformation. A viewer option such as “fit on one page” may resize the page after the PDF's own drawing operations have been interpreted, and printer settings can affect the final mark. If a page contains several nested transforms, render the same path once with the additional scale and once without it, keeping its coordinates and width unchanged. That isolates the contribution of the matrix without asking the line itself to change. For a raster result, examine pixels at the actual output resolution instead of measuring a bitmap that has been enlarged by the display application

Choose the right width for the job

Choose the width according to what you need the drawing to express. A zero-width hairline is useful for a mark intended to remain fine at the output device; a specified physical line weight calls for a positive width expressed in the appropriate page coordinate system. Keep both cases in your rendering pipeline: the hairline exercises the device-width rule, while a known positive width under a known transform exercises geometric scaling. A third case with a large numeric width and a small scale is worth adding because it exposes shortcuts based only on the magnitude of the untransformed number. Test the physical-width requirement on the device or print workflow that will produce the drawing

Thumbnail generation introduces another fit calculation, often after the original page has already been rendered or measured. A rule that appears heavier in a thumbnail may reflect that presentation scale rather than a change in the PDF path. For a batch report, document whether the thin mark is intended as a device hairline or as a measured stroke; that decision tells a later maintainer which output behavior to preserve when changing thumbnail or print settings. The same source page can be rendered at the original size and at the thumbnail scale, making the added presentation step visible in the resulting images

The graphics-state and clipping guide follows transformations through a content stream, while vector graphics and shading covers other drawing operations. The Delphi rendering API belongs to PDF Library for Delphi