Skip to main content

pdfrum_page/
lib.rs

1#![doc = include_str!("../README.md")]
2// The two stages are a pipeline of pure functions:
3//
4//     bytes ──parse_content──▶ Vec<Op> ──build_page──▶ Page { objects, boxes }
5//
6// `parse_content` tokenizes, fills a sixteen-slot operand ring, and emits one
7// `Op` per recognised operator. `build_page` is the fold that turns those
8// operators into page objects, and it is where resources, the graphics-state
9// stack and form recursion live. Separating them means a content stream can be
10// inspected, diffed and fuzzed without a document, and a page can be built from
11// synthesized operators without bytes.
12//
13// Damage is data, not failure: the best-effort results match what PDFium
14// produces, because that behaviour is what makes broken PDFs render.
15#![forbid(unsafe_code)]
16#![cfg_attr(docsrs, feature(doc_cfg))]
17// Every byte reaching this crate came from an untrusted file: index with
18// `get()` and do arithmetic with `checked_*`.
19#![warn(clippy::indexing_slicing)]
20
21mod build;
22mod color;
23mod content;
24mod error;
25mod function;
26mod image;
27mod inline_image;
28mod mutate;
29mod names;
30mod ops;
31mod optional;
32mod page;
33mod page_edit;
34mod pattern;
35// The whole-render stage timers. Public *with the default-off `profiling`
36// feature and only then*: the module always exists, because the render calls
37// its entry points unconditionally and they compile to empty inline functions
38// with the feature off, but its reporting items are part of the instrument
39// rather than of the crate a `cargo add pdfrum-page` reaches. Same argument
40// and same shape as `pdfrum_render::walkprofile`: the committed API
41// snapshots deliberately do not cover the `profiling` feature, because its
42// items are not part of the published surface.
43//
44// The two crates above this one time their own stages, so they forward a
45// `profiling` of their own and gate their call sites on it: a caller cannot
46// `#[cfg]` on another crate's feature, and leaving this module unconditionally
47// public so they need not is a surface with no reader in the default build.
48#[cfg(feature = "profiling")]
49pub mod renderprofile;
50#[cfg(not(feature = "profiling"))]
51mod renderprofile;
52mod resources;
53mod shading;
54mod state;
55mod tokenize;
56mod transfer;
57mod transparency;
58mod type3;
59
60pub use build::{
61    BuildContext, FormFontsKey, FoundPattern, MAX_FORM_LEVEL, StreamBounds, build_form_object,
62    build_form_object_with, build_page, build_page_from_dict, build_page_streams,
63    eliminate_redundant_clips, load_pattern,
64};
65pub use color::{
66    ColorSpace, ColorValue, Family, PatternSpace, PatternValue, Rgb, Separation,
67    SetComponentsError, adobe_cmyk_to_srgb, cmyk_profile_bytes, load_colorspace,
68    srgb_profile_bytes,
69};
70pub use content::parse_content;
71pub use error::Error;
72pub use function::{Function, FunctionCache, PostScript, parse_program};
73#[cfg(feature = "jbig2")]
74pub use image::decode_jbig2;
75pub use image::{
76    BitImage, Converted, Depth, ImageCache, ImageData, ImageMask, MAX_BYTES, MAX_IMAGE_PIXELS,
77    Packed, Palette, Pixels, RequestedSize, Rgb8, Rgba8, Row, Rows, Samples, Source, Unpacked,
78    decode_image, image_area_is_workable,
79};
80#[cfg(feature = "jpeg2000")]
81pub use image::{JpxImage, decode_jpx};
82pub use mutate::IndexOutOfRange;
83pub use ops::{
84    FillRule, InlineImage, LineCap, LineJoin, MarkProperties, Op, TextItem, TextRenderMode,
85};
86pub use optional::{OcContext, UsageType, Visibility, page_visibility};
87pub use page::{
88    Content, DEFAULT_MEDIA_BOX, FormObject, ImageObject, NotAQuarterTurn, Page, PageObject,
89    PathObject, Rotation, ShadingObject, TextObject, TextSegment, derive_boxes,
90    display_size_from_dict,
91};
92pub use page_edit::{PageEdit, transform_object};
93pub use pattern::{Pattern, ShadingPattern, TileRange, TilingPattern, uncolored_pattern_rgb};
94pub use resources::Resources;
95pub use shading::{
96    Axial, FunctionBased, Geometry, Mesh, MeshParams, MeshReader, Patch, Radial, Shading,
97    ShadingKind, ShadingSource, Triangle, Vertex, coons_interior,
98};
99pub use state::{
100    BlendMode, ClipEntry, ClipRule, ClipStack, ContentMarks, GeneralState, GraphicsState,
101    MAX_TEXT_OBJECTS, Mark, StateStack, StrokeParams, TextClipLimit, TextClipRun, TextState,
102    apply_ext_gstate,
103};
104pub use transfer::{CHANNEL_SAMPLES, TransferFunc};
105pub use transparency::{SoftMask, SoftMaskKind, Transparency};
106pub use type3::Type3Metrics;
107
108#[cfg(test)]
109mod send_sync {
110    // Rendering pages in parallel with rayon must Just Work.
111    const fn assert_send_sync<T: Send + Sync>() {}
112
113    #[test]
114    fn public_types_are_send_and_sync() {
115        assert_send_sync::<crate::Op>();
116        assert_send_sync::<crate::ColorSpace>();
117        assert_send_sync::<crate::Function>();
118        assert_send_sync::<crate::Shading>();
119        assert_send_sync::<crate::Pattern>();
120        assert_send_sync::<crate::ImageData>();
121        assert_send_sync::<crate::Error>();
122    }
123}