Technical Article

Reading Two-Column PDFs in Delphi Without Mixing the Columns

Copy text from a two-column research paper and the output can alternate between left and right lines. PDFium Component can order untagged reader output by columns, treating a full-width heading or caption as a flow band while preserving the original text and page locations

The page can look like a carefully typeset article without containing an instruction to read the left column first. A PDF content stream describes where text is painted, and its paint order can reflect the producer's graphics operations, font changes or other construction choices. For heuristic readable content, PDFium Component offers an optional geometric column-ordering step. It examines extracted fragment positions, recognizes objects spanning a candidate gutter and returns a reordered reading snapshot without rewriting the page. When a document has usable tagged structure, begin with that logical order: it can express relationships that the visual arrangement alone does not provide

Why does a top-to-bottom sort mix columns?

A top-to-bottom sort works until two newspaper columns occupy the same horizontal band. It may read a line from the left, jump to the right, then return to the left for the next line. That sequence fits some table rows and ruins an ordinary paragraph. Sorting by horizontal position alone has its own problem: a full-width heading crosses the gap between columns and can join both sides into one large cluster. PDFium Component looks for a candidate gutter and distinguishes the objects on either side from those that span it. A spanning caption becomes a boundary in the flow: read the columns above it, read the caption, then continue with the columns below. We would give users of a general reader a way to return to native order, because the geometry that makes a journal article readable may be the wrong rule for a page built as a table

Enable the column heuristic

The default is rhoNative. Set TPdfReadableContentOptions.HeuristicOrder to rhoColumns when the application wants geometric ordering for heuristic reader output. The Delphi example configures an existing TPdf after loading its document

uses
  PDFium;

procedure EnableColumnReading(Pdf: TPdf);
var
  Options: TPdfReadableContentOptions;
begin
  Options := TPdfReadableContentOptions.Default;
  Options.HeuristicOrder := rhoColumns;
  Options.ColumnGap := 18;
  Options.RightToLeft := False;
  Pdf.ReadableContentOptions := Options;
end;

Request readable content or reading units after you set the options. ColumnGap is measured in points and defaults to 18. When columns progress from right to left, set RightToLeft; it controls the column order and horizontal tie order, rather than converting the language or rewriting individual glyph directions. The setting applies to heuristic output. Usable tagged logical content remains in its structure order, so a geometric guess about a page does not replace an author's explicit reading structure

Read the result as a snapshot

A transcript can be correct while its highlight lands in the neighboring column. That happens if a reader reorders the words but loses their connection to their source locations. PDFium Component keeps the source text, MCID and original page-space rectangle for each fragment in the reading snapshot. Intrinsic page rotation is considered when deriving displayed bounds for ordering; the PDF's stored coordinates are not rewritten. Selection and speech therefore need to be checked together. Read the words in the expected order, then check that you can navigate back to them using the source rectangle, particularly on a rotated page. The fragment's place in the output sequence and its physical location on the page answer different parts of the user interaction

How do you know whether column ordering ran?

ReadableContent.HeuristicOrderApplied tells the application whether geometric ordering was applied, and DetectedColumns reports the maximum number of columns in a flow band. Read those values while you follow the returned fragment sequence rather than assuming that enabling an option forces a column arrangement on every page. Run the following routine after selecting the page and configuring the options

procedure DumpPageReadingOrder(Pdf: TPdf);
var
  Content: TPdfReadableContent;
  I: Integer;
begin
  Content := Pdf.ReadableContent;
  Writeln('Column order applied: ', Content.HeuristicOrderApplied);
  Writeln('Detected columns: ', Content.DetectedColumns);
  for I := 0 to High(Content.Fragments) do
    Writeln(I, ': ', Content.Fragments[I].Text);
end;

For a page with a title and two columns, the expected sequence begins with the title and then the first column. If the flag is false, report the native order. A candidate gutter needs content on both sides with overlapping vertical extents; the heuristic requires at least two objects on each side, which reduces the chance that one marginal note becomes a second column. When the geometry cannot be ordered within the available work limits, the reader keeps the complete native sequence rather than returning a partially sorted page. That fallback is useful to a host application because it can present the extraction result without claiming that the column heuristic was applied

The user interface can reflect that fallback. Offer a column-order setting, but leave a route back to native order when the input contains tables, sidebars or other layouts that call for a different sequence. A detected column count is not a document-wide label. One page may contain two columns above a caption and a single wide section below it; the reported maximum describes the strongest separation found in a flow band. For a reading-order report, record the page, whether the heuristic was applied and the extracted sequence. Fragment rectangles can overlap in ways that are not obvious from the page's visual appearance, particularly after rotation. A page-level status is more informative than a single document-wide label here: the reader may find a clear gutter on one page and retain native order on the next. Presenting the applied flag with each page's result makes that behavior visible to the host application

Start with a page whose column boundaries you can identify

Create a page with a full-width title, two columns containing at least two text objects each, and a full-width caption between two column regions. You can use distinct labels such as LEFT ONE, LEFT TWO, RIGHT ONE and RIGHT TWO, so the sequence is easy to identify. Add a rotated page and a right-to-left layout, then read them with the heuristic disabled and enabled. Select words on both sides and verify that each highlight lands on its source text. Saving and reopening the PDF should leave the page content in place: the reader order is an application snapshot, not a rearrangement of the content stream

Real document collections also contain footnotes, sidebars, tables and overlapping labels. Choose a default based on the documents you expect the audience to read rather than assuming that one geometry rule suits all pages. A useful boundary case is a heading that looks full-width but ends just before the gutter. Its extracted rectangle determines whether it crosses the candidate split, so two headings that look similar on screen can be classified differently. When the result is unexpected, read the fragment bounds at the chosen page rotation and follow their positions through the reported sequence. That gives the application something concrete to diagnose before changing the ordering option. For a caption that spans the gutter, look at the flow above and below it independently. The reported maximum number of columns describes a flow band; it does not mean that a wide caption or a later single-column section should be read as if it had two columns

The structured text and reading order guide explains the surrounding extraction model, and the accessible reader guide covers reading units and navigation. These Delphi options belong to PDFium Component