A vector graphics path — a line, curve, rectangle, or filled shape — extracted from a PDF page, with its zero-based page index and bounding box.
The :operations field holds the path's drawing commands as a list of flat
tagged tuples, in stream order:
{:move_to, x, y}— start a new subpath at(x, y){:line_to, x, y}— straight line to(x, y){:curve_to, c1x, c1y, c2x, c2y, ex, ey}— cubic Bézier curve (the two control points and the endpoint){:rectangle, x, y, width, height}— a complete rectangle subpath:close_path— close the current subpath
A path may be stroked, filled, or both: :stroke_color and :fill_color are
each a PdfElixide.Color.RGB or nil. Upstream resolves every colorspace to
DeviceRGB during extraction, so these are always RGB — never the other
PdfElixide.Color structs.
Rectangles and straight lines
PdfElixide.Document.rects/2 and PdfElixide.Document.lines/2 return these
same structs, narrowed by a test of :operations alone — of the drawing
commands, not of the geometry they describe:
- a rectangle is a lone
{:rectangle, …}, or a{:move_to, …}followed by exactly three{:line_to, …}, optionally then:close_path; - a straight line is a
{:move_to, …}followed by exactly one{:line_to, …}, optionally then:close_path.
(Those are vector graphics; PdfElixide.Document.text_lines/2 is the
unrelated text extractor.) The two sets are therefore disjoint subsets of
paths/2, with four consequences:
- A rectangle drawn back to its starting corner is classified as
neither — one
{:line_to, …}too many. Boxes drawn with thereoperator, the usual case, are unaffected. - Four points on one straight line are classified as a rectangle, and
arrive with a zero-height or zero-width
:bbox. - Degenerate shapes are kept, so filter on
:bboxif you need shapes with extent. - A curve disqualifies a path entirely. A rounded rectangle is neither.
Each call runs a full extraction of the page, so asking one page for both its rectangles and its lines costs twice what asking for either does.
One shape reaches none of the three: a path painted with B, B* or b*
(fill and stroke together) is not extracted at all, and its commands are
prepended to the next path — changing that path's operation count, so a
rectangle or line drawn right after one goes missing too.
Summary
Types
@type operation() :: {:move_to, float(), float()} | {:line_to, float(), float()} | {:curve_to, float(), float(), float(), float(), float(), float()} | {:rectangle, float(), float(), float(), float()} | :close_path
A single drawing command in a path's :operations list.
@type t() :: %PdfElixide.Document.Path{ bbox: PdfElixide.Geometry.Rect.t(), dash_pattern: {[float()], float()} | nil, fill_color: PdfElixide.Color.RGB.t() | nil, layer: String.t() | nil, line_cap: :butt | :round | :square, line_join: :miter | :round | :bevel, operations: [operation()], page: non_neg_integer(), stroke_color: PdfElixide.Color.RGB.t() | nil, stroke_width: float() }