Skip to main content

PathContent

Struct PathContent 

Source
pub struct PathContent {
    pub bbox: Rect,
    pub operations: Vec<PathOperation>,
    pub stroke_color: Option<Color>,
    pub fill_color: Option<Color>,
    pub stroke_width: f32,
    pub line_cap: LineCap,
    pub line_join: LineJoin,
    pub dash_pattern: Option<(Vec<f32>, f32)>,
    pub matrix: Option<[f32; 6]>,
    pub reading_order: Option<usize>,
    pub artifact_type: Option<ArtifactType>,
    pub layer: Option<String>,
}
Expand description

Vector path content that can be extracted from or written to a PDF.

This represents vector graphics such as lines, curves, and shapes.

Fields§

§bbox: Rect

Bounding box of the path

§operations: Vec<PathOperation>

Path operations

§stroke_color: Option<Color>

Stroke color (None for no stroke)

§fill_color: Option<Color>

Fill color (None for no fill)

§stroke_width: f32

Stroke width in points

§line_cap: LineCap

Line cap style

§line_join: LineJoin

Line join style

§dash_pattern: Option<(Vec<f32>, f32)>

Optional dash pattern: Some((dashes, phase)) emits a [dashes...] phase d operator before stroking. dashes is on/ off lengths in points (e.g. [3.0, 2.0] = dash 3 pt, gap 2 pt, repeating); phase is the starting offset. None leaves the line solid.

§matrix: Option<[f32; 6]>

Optional 2D affine transform in PDF row order [a b c d e f]. When set, the path is wrapped in q ... cm ... Q on emission so graphics-state stays scoped. Populated by FluentPageBuilder::{rotated, scaled, translated, with_transform} closures — v0.3.39 (text-only) extended here to cover paths. #393 Bundle A-2 follow-up.

§reading_order: Option<usize>

Reading order index

§artifact_type: Option<ArtifactType>

When set, this path is wrapped in /Artifact <</Type /T>> BDC … EMC markers so accessibility tools can skip it. Useful for decorative separator lines (footnote rules, header/footer rules).

§layer: Option<String>

Optional Content Group (PDF “layer”) name resolved from the surrounding BDC /OC … EMC markers in the content stream. Set during path extraction by PathExtractor when an OCG is active; None for paths emitted outside any /OC-tagged marked-content region or in PDFs that do not declare optional content.

The string is the human-readable /Name entry of the referenced OptionalContentGroup, e.g. "A-GRID", "S-COLS", "A-WALL-DIM" for PDFs exported from Revit/AutoCAD with layer metadata intact. Reference: ISO 32000-1:2008 §8.11 (Optional Content) + §14.6 (Marked Content).

Implementations§

Source§

impl PathContent

Source

pub const PAGE_FRAME_COVERAGE_THRESHOLD: f32 = 0.9

True when this path is a rectangle covering at least this fraction of the MediaBox in both dimensions. 0.9 leaves generous margin for a page background that stops just short of the trim box while still rejecting anything smaller than page furniture — a genuine table spanning most of a page’s text column is still well under 90% of the full MediaBox once margins are accounted for. GH#1656. ~keep

Source

pub fn new(bbox: Rect) -> Self

Create a new empty path content element.

Source

pub fn from_operations(operations: Vec<PathOperation>) -> Self

Create a path from operations.

Source

pub fn with_stroke(self, color: Color) -> Self

Set stroke color.

Source

pub fn with_fill(self, color: Color) -> Self

Set fill color.

Source

pub fn with_stroke_width(self, width: f32) -> Self

Set stroke width.

Source

pub fn with_reading_order(self, order: usize) -> Self

Set reading order.

Source

pub fn with_layer(self, layer: impl Into<String>) -> Self

Set the Optional Content Group (PDF “layer”) name. Used by PathExtractor while walking the content stream to attach the active OCG name to each extracted path.

Source

pub fn push(&mut self, op: PathOperation)

Add a path operation.

Source

pub fn has_stroke(&self) -> bool

Check if this path has a stroke.

Source

pub fn has_fill(&self) -> bool

Check if this path has a fill.

Source

pub fn is_straight_line(&self) -> bool

Check if this path represents a single straight line (v0.3.14).

A path is a straight line if it has exactly 2 operations: MoveTo followed by LineTo.

Source

pub fn rendered_bbox(&self) -> Rect

Rendered extents of this path: the geometric bbox inflated by the stroke (ISO 32000-1:2008 §8.4.3.2 — half the line width straddles each side of the path).

Print-era producers draw a table’s vertical rule as a ~1 pt horizontal segment stroked as wide as the table is tall, so the geometric bbox (1×0 pt) bears no resemblance to the bar the reader sees. Classifiers that reason about what is rendered (line orientation, table primitives, region hit-testing) should use this; consumers that need the raw path geometry (corner tests, SVG path data, editing) keep bbox.

For a single straight segment the inflation is exact: half the stroke width perpendicular to the segment, plus the cap extension along it (Butt caps add nothing axially; Round/Square add half the width per end, §8.4.3.3). For any other shape the bbox is inflated by half the width on all four sides — a conservative superset that is exact for axis-aligned stroked outlines.

Unstroked paths return bbox unchanged.

Source

pub fn is_horizontal_line(&self, tolerance: f32) -> bool

Check if this path is a horizontal line within a tolerance (v0.3.16).

tolerance bounds the geometric minor extent as before (a nearly axis-aligned segment or sliver rectangle). Orientation is then confirmed on the rendered_bbox: a 1 pt segment stroked 430 pt wide renders as a vertical bar and must not classify as a horizontal line just because its raw geometry is a horizontal speck.

Source

pub fn is_vertical_line(&self, tolerance: f32) -> bool

Check if this path is a vertical line within a tolerance (v0.3.16).

Same contract as is_horizontal_line: geometric thinness within tolerance, orientation confirmed on the rendered extents.

Source

pub fn is_nearly_touching(&self, other: &Rect, tolerance: f32) -> bool

Check if this path’s bounding box is nearly touching another (v0.3.16).

Source

pub fn is_rectangle(&self) -> bool

Check if this path represents a single rectangle (v0.3.14).

A path is a rectangle if it has exactly 1 operation: Rectangle, or if it has 5 operations: MoveTo, 3x LineTo, ClosePath that form a rectangle.

Source

pub fn is_table_primitive(&self) -> bool

Check if this path is “box-like” or “line-like” based on its dimensions (v0.3.16). This is a fuzzy heuristic for table detection.

Line length is judged on the rendered_bbox while thinness stays geometric, so a table rule encoded as a short segment with a table-height stroke width — a 1×0 pt geometric speck rendering as a 1×430 pt bar — is recognized as the ruling it draws , and an ordinary rule with a thick stroke keeps classifying as a line exactly as before.

Thresholds (inherited from the v0.3.16 heuristic): a ruling must run more than 5 pt — half an em at 10 pt body text — so tick marks and list bullets don’t qualify; it must be under 2 pt across, twice the heaviest common ruling weight (typical PDF rules are 0.5–1 pt) while safely below any filled cell; and a box must stay under 1000 pt per side so absurdly large shapes (chart backgrounds, full artboards) don’t seed a cluster on their own.

GH#1656: 1000 pt does not exclude an ordinary page — A4 (595×842) and US-Letter (612×792) both pass this bound, so a full-page background rectangle (common Office-to-PDF output) is accepted here as a table primitive and can cluster with every other primitive on the page. This function has no access to the page’s MediaBox (PathContent carries no page dimensions), so it cannot make that call itself. Page-relative filtering of such furniture happens one level up, in PdfDocument::extract_tables_with_config and PdfDocument::extract_page_tables (document/tables.rs), which use PathContent::is_page_frame_rectangle against the real MediaBox before primitives reach the clusterer in spatial_table_detector.rs. ~keep

Source

pub fn is_page_frame_rectangle(&self, media_box: (f32, f32, f32, f32)) -> bool

True when this path is a rectangle spanning at least PAGE_FRAME_COVERAGE_THRESHOLD of media_box in both width and height — page furniture (a full-bleed background fill, a decorative frame) rather than a table primitive. GH#1656: is_table_primitive’s < 1000 pt bound admits ordinary page-sized rectangles (A4, Letter), which then seed a whole-page false-positive cluster; this predicate is how callers with access to the page’s MediaBox (PathContent itself carries none) can exclude that furniture before it reaches the clusterer.

media_box is (llx, lly, urx, ury) as returned by PdfDocument::get_page_media_box. Requiring both dimensions to clear the threshold is deliberate: a full-page-width footer rule (wide, but a fraction of a point tall) must not be classified as page furniture and dropped — it is a legitimate table/ruling primitive. A degenerate media_box (zero or negative area, non-finite) can’t establish “most of the page”, so this returns false — callers should treat a failed MediaBox lookup as “leave every primitive alone”, not as license to filter on garbage. ~keep

Source

pub fn line(x1: f32, y1: f32, x2: f32, y2: f32) -> Self

Create a line path from (x1, y1) to (x2, y2).

§Example
ⓘ
let line = PathContent::line(10.0, 10.0, 100.0, 100.0);
Source

pub fn rect(x: f32, y: f32, width: f32, height: f32) -> Self

Create a rectangle path.

§Example
ⓘ
let rect = PathContent::rect(10.0, 10.0, 100.0, 50.0);
Source

pub fn circle(cx: f32, cy: f32, radius: f32) -> Self

Create an approximate circle path using Bezier curves.

Uses 4 cubic Bezier curves to approximate a circle. The approximation uses the constant k = 0.5522847498 for control points.

§Example
ⓘ
let circle = PathContent::circle(100.0, 100.0, 50.0);
Source

pub fn rounded_rect( x: f32, y: f32, width: f32, height: f32, radius: f32, ) -> Self

Create a rounded rectangle path.

§Arguments
  • x - X coordinate of the bottom-left corner
  • y - Y coordinate of the bottom-left corner
  • width - Width of the rectangle
  • height - Height of the rectangle
  • radius - Corner radius (clamped to min(width, height) / 2)
§Example
ⓘ
let rounded = PathContent::rounded_rect(10.0, 10.0, 100.0, 50.0, 5.0);
Source

pub fn to_points(&self, tolerance: f32) -> Vec<Vec<(f32, f32)>>

Flatten this path into polylines — one Vec<(x, y)> per subpath.

Straight segments (MoveTo/LineTo) pass through unchanged; cubic Béziers (CurveTo) are adaptively subdivided so the resulting polyline stays within tolerance of the true curve. A Rectangle becomes its own closed 5-point subpath, and ClosePath appends the subpath’s start point. A new subpath begins at every MoveTo (and every Rectangle).

tolerance is expressed in the same coordinate space as the path’s own points, and the returned points are in that space verbatim. For paths from crate::document::PdfDocument::extract_paths that is the page’s default user space (PDF points, y-up), with any content-stream cm and Form-XObject /Matrix transforms already folded in — so a path drawn under a scaling transform is returned (and flattened) at its final on-page size, and no tolerance rescaling is needed. It is not device or pixel space: page /Rotate and rendering DPI are not applied. Smaller values yield more, finer points. A non-positive or non-finite tolerance is floored to a small epsilon so subdivision always terminates.

This is intended for consumers that need sampled coordinates rather than drawing operators — e.g. digitising chart/ECG/CAD traces from vector PDFs.

§Examples
use xberg_native_pdf::elements::{PathContent, PathOperation};

let path = PathContent::from_operations(vec![
    PathOperation::MoveTo(0.0, 0.0),
    PathOperation::CurveTo(0.0, 10.0, 10.0, 10.0, 10.0, 0.0),
]);
let subpaths = path.to_points(0.25);
assert_eq!(subpaths.len(), 1);
assert_eq!(subpaths[0][0], (0.0, 0.0)); // starts at P0

Trait Implementations§

Source§

impl Clone for PathContent

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for PathContent

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for PathContent

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl LayoutObjectSpatial for PathContent

Source§

fn bbox(&self) -> Rect

Get the bounding box of the object.
Source§

fn intersects_rect(&self, rect: &Rect) -> bool

Check if this object intersects with the given rectangle.
Source§

fn contained_in_rect(&self, rect: &Rect) -> bool

Check if this object is fully contained within the given rectangle.
Source§

fn overlap_with_rect(&self, rect: &Rect) -> f32

Calculate the overlap fraction (0.0-1.0) with the given rectangle. Read more
Source§

fn matches_filter(&self, rect: &Rect, mode: RectFilterMode) -> bool

Check if this object matches the given filter mode for a rectangle.
Source§

impl Serialize for PathContent

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more