oxidize_pdf/
lib.rs

1//! # oxidize-pdf
2//!
3//! A comprehensive, pure Rust PDF library for generation, parsing, and manipulation with zero external PDF dependencies.
4//!
5//! ## Features
6//!
7//! - **PDF Generation**: Create multi-page documents with text, graphics, and images
8//! - **PDF Parsing**: Complete parser supporting rendering and content extraction
9//! - **PDF Operations**: Split, merge, rotate, and extract pages
10//! - **Text Extraction**: Extract text with position and formatting information
11//! - **Resource Access**: Work with fonts, images, and other PDF resources
12//! - **Pure Rust**: No C dependencies or external libraries
13//! - **100% Native**: Complete PDF implementation from scratch
14//!
15//! ## Quick Start
16//!
17//! ### Creating PDFs
18//!
19//! ```rust
20//! use oxidize_pdf_core::{Document, Page, Font, Color, Result};
21//!
22//! # fn main() -> Result<()> {
23//! // Create a new document
24//! let mut doc = Document::new();
25//! doc.set_title("My PDF");
26//!
27//! // Create a page
28//! let mut page = Page::a4();
29//!
30//! // Add text
31//! page.text()
32//!     .set_font(Font::Helvetica, 24.0)
33//!     .at(50.0, 700.0)
34//!     .write("Hello, PDF!")?;
35//!
36//! // Add graphics
37//! page.graphics()
38//!     .set_fill_color(Color::rgb(0.0, 0.5, 1.0))
39//!     .circle(300.0, 400.0, 50.0)
40//!     .fill();
41//!
42//! // Save the document
43//! doc.add_page(page);
44//! doc.save("output.pdf")?;
45//! # Ok(())
46//! # }
47//! ```
48//!
49//! ### Parsing PDFs
50//!
51//! ```rust,no_run
52//! use oxidize_pdf_core::parser::{PdfDocument, PdfReader};
53//!
54//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
55//! // Open and parse a PDF
56//! let reader = PdfReader::open("document.pdf")?;
57//! let document = PdfDocument::new(reader);
58//!
59//! // Get document information
60//! println!("Pages: {}", document.page_count()?);
61//! println!("Version: {}", document.version()?);
62//!
63//! // Process pages
64//! for i in 0..document.page_count()? {
65//!     let page = document.get_page(i)?;
66//!     println!("Page {} size: {}x{} points", i+1, page.width(), page.height());
67//! }
68//!
69//! // Extract text
70//! let text_pages = document.extract_text()?;
71//! for (i, page_text) in text_pages.iter().enumerate() {
72//!     println!("Page {} text: {}", i+1, page_text.text);
73//! }
74//! # Ok(())
75//! # }
76//! ```
77//!
78//! ## Modules
79//!
80//! ### Generation Modules
81//! - [`document`] - PDF document creation and management
82//! - [`page`] - Page creation and layout
83//! - [`graphics`] - Vector graphics and images
84//! - [`text`] - Text rendering and flow
85//! - [`writer`] - Low-level PDF writing
86//!
87//! ### Parsing Modules
88//! - [`parser`] - Complete PDF parsing and reading
89//!   - [`parser::PdfDocument`] - High-level document interface
90//!   - [`parser::ParsedPage`] - Page representation with resources
91//!   - [`parser::ContentParser`] - Content stream parsing
92//!   - [`parser::PdfObject`] - Low-level PDF objects
93//!
94//! ### Manipulation Modules
95//! - [`operations`] - PDF manipulation (split, merge, rotate)
96//! - [`text::extraction`] - Text extraction with positioning
97//!
98//! ## Examples
99//!
100//! ### Content Stream Processing
101//!
102//! ```rust,no_run
103//! use oxidize_pdf_core::parser::{PdfDocument, PdfReader};
104//! use oxidize_pdf_core::parser::content::{ContentParser, ContentOperation};
105//!
106//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
107//! let reader = PdfReader::open("document.pdf")?;
108//! let document = PdfDocument::new(reader);
109//! let page = document.get_page(0)?;
110//!
111//! // Get and parse content streams
112//! let streams = page.content_streams_with_document(&document)?;
113//! for stream in streams {
114//!     let operations = ContentParser::parse(&stream)?;
115//!     
116//!     for op in operations {
117//!         match op {
118//!             ContentOperation::ShowText(text) => {
119//!                 println!("Text: {:?}", String::from_utf8_lossy(&text));
120//!             }
121//!             ContentOperation::SetFont(name, size) => {
122//!                 println!("Font: {} at {} pt", name, size);
123//!             }
124//!             ContentOperation::MoveTo(x, y) => {
125//!                 println!("Move to ({}, {})", x, y);
126//!             }
127//!             _ => {} // Handle other operations
128//!         }
129//!     }
130//! }
131//! # Ok(())
132//! # }
133//! ```
134//!
135//! ### Resource Access
136//!
137//! ```rust,no_run
138//! use oxidize_pdf_core::parser::{PdfDocument, PdfReader};
139//!
140//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
141//! let reader = PdfReader::open("document.pdf")?;
142//! let document = PdfDocument::new(reader);
143//! let page = document.get_page(0)?;
144//!
145//! // Access page resources
146//! if let Some(resources) = page.get_resources() {
147//!     // Check fonts
148//!     if let Some(fonts) = resources.get("Font").and_then(|f| f.as_dict()) {
149//!         for (name, _) in &fonts.0 {
150//!             println!("Font resource: {}", name.as_str());
151//!         }
152//!     }
153//!     
154//!     // Check images/XObjects
155//!     if let Some(xobjects) = resources.get("XObject").and_then(|x| x.as_dict()) {
156//!         for (name, _) in &xobjects.0 {
157//!             println!("XObject resource: {}", name.as_str());
158//!         }
159//!     }
160//! }
161//! # Ok(())
162//! # }
163//! ```
164
165pub mod document;
166pub mod error;
167pub mod graphics;
168pub mod objects;
169pub mod operations;
170pub mod page;
171pub mod parser;
172pub mod text;
173pub mod writer;
174
175#[cfg(feature = "semantic")]
176pub mod semantic;
177
178// Re-export generation types
179pub use document::{Document, DocumentMetadata};
180pub use error::{OxidizePdfError, PdfError, Result};
181pub use graphics::{Color, GraphicsContext, Image, ImageColorSpace, ImageFormat};
182pub use page::{Margins, Page};
183pub use text::{
184    measure_text, split_into_words, Font, FontFamily, TextAlign, TextContext, TextFlowContext,
185};
186
187// Re-export parsing types
188pub use parser::{
189    ContentOperation, ContentParser, DocumentMetadata as ParsedDocumentMetadata,
190    ParsedPage, PdfArray, PdfDictionary, PdfDocument, PdfName, PdfObject, 
191    PdfReader, PdfStream, PdfString,
192};
193
194// Re-export operations
195pub use operations::{merge_pdfs, rotate_pdf_pages, split_pdf};
196
197/// Current version of oxidize-pdf
198pub const VERSION: &str = env!("CARGO_PKG_VERSION");
199
200/// Supported PDF versions
201pub mod pdf_version {
202    /// PDF 1.0 - 1.7 are fully supported
203    pub const SUPPORTED_VERSIONS: &[&str] = &["1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7"];
204    /// PDF 2.0 support is planned
205    pub const PLANNED_VERSIONS: &[&str] = &["2.0"];
206}
207
208#[cfg(test)]
209mod tests {
210    use super::*;
211
212    #[test]
213    fn test_create_empty_document() {
214        let doc = Document::new();
215        assert_eq!(doc.pages.len(), 0);
216    }
217
218    #[test]
219    fn test_create_page() {
220        let page = Page::new(595.0, 842.0);
221        assert_eq!(page.width(), 595.0);
222        assert_eq!(page.height(), 842.0);
223    }
224    
225    #[test]
226    fn test_version_info() {
227        assert!(!VERSION.is_empty());
228        assert!(pdf_version::SUPPORTED_VERSIONS.contains(&"1.7"));
229    }
230}