xberg_native_pdf/document/
rect_api.rs1use super::*;
8
9impl PdfDocument {
10 pub fn extract_text_in_rect(
18 &self,
19 page_index: usize,
20 region: crate::geometry::Rect,
21 mode: crate::layout::RectFilterMode,
22 ) -> Result<String> {
23 let options = crate::converters::ConversionOptions {
24 extract_tables: true,
25 include_region: Some((region, mode)),
26 ..Default::default()
27 };
28 self.extract_text_with_options(page_index, &options)
29 }
30
31 pub fn extract_words_in_rect(
33 &self,
34 page_index: usize,
35 region: crate::geometry::Rect,
36 mode: crate::layout::RectFilterMode,
37 ) -> Result<Vec<crate::layout::Word>> {
38 use crate::layout::SpatialCollectionFiltering;
39 let words = self.extract_words(page_index)?;
40 Ok(words.filter_by_rect(®ion, mode))
41 }
42
43 pub fn extract_text_lines_in_rect(
45 &self,
46 page_index: usize,
47 region: crate::geometry::Rect,
48 mode: crate::layout::RectFilterMode,
49 ) -> Result<Vec<crate::layout::TextLine>> {
50 use crate::layout::SpatialCollectionFiltering;
51 let lines = self.extract_text_lines(page_index)?;
52 Ok(lines.filter_by_rect(®ion, mode))
53 }
54
55 pub fn extract_spans_in_rect(
57 &self,
58 page_index: usize,
59 region: crate::geometry::Rect,
60 mode: crate::layout::RectFilterMode,
61 ) -> Result<Vec<crate::layout::TextSpan>> {
62 use crate::layout::SpatialCollectionFiltering;
63 let spans = self.extract_spans(page_index)?;
64 Ok(spans.filter_by_rect(®ion, mode))
65 }
66
67 pub fn extract_text_excluding_rects(
86 &self,
87 page_index: usize,
88 exclude: &[crate::geometry::Rect],
89 mode: crate::layout::RectFilterMode,
90 ) -> Result<String> {
91 let options = crate::converters::ConversionOptions {
92 extract_tables: true,
93 exclude_regions: exclude.to_vec(),
94 exclude_regions_mode: mode,
95 ..Default::default()
96 };
97 self.extract_text_with_options(page_index, &options)
98 }
99
100 pub fn extract_words_excluding_rects(
106 &self,
107 page_index: usize,
108 exclude: &[crate::geometry::Rect],
109 mode: crate::layout::RectFilterMode,
110 ) -> Result<Vec<crate::layout::Word>> {
111 use crate::layout::SpatialCollectionFiltering;
112 let words = self.extract_words(page_index)?;
113 Ok(words.exclude_rects(exclude, mode))
114 }
115
116 pub fn extract_spans_excluding_rects(
122 &self,
123 page_index: usize,
124 exclude: &[crate::geometry::Rect],
125 mode: crate::layout::RectFilterMode,
126 ) -> Result<Vec<crate::layout::TextSpan>> {
127 use crate::layout::SpatialCollectionFiltering;
128 let spans = self.extract_spans(page_index)?;
129 Ok(spans.exclude_rects(exclude, mode))
130 }
131
132 pub fn extract_rects_in_rect(
134 &self,
135 page_index: usize,
136 region: crate::geometry::Rect,
137 ) -> Result<Vec<crate::elements::PathContent>> {
138 let rects = self.extract_rects(page_index)?;
139 Ok(rects
141 .into_iter()
142 .filter(|p| p.rendered_bbox().intersects(®ion))
143 .collect())
144 }
145
146 pub fn extract_lines_in_rect(
148 &self,
149 page_index: usize,
150 region: crate::geometry::Rect,
151 ) -> Result<Vec<crate::elements::PathContent>> {
152 let lines = self.extract_lines(page_index)?;
153 Ok(lines
157 .into_iter()
158 .filter(|p| p.rendered_bbox().intersects(®ion))
159 .collect())
160 }
161
162 pub fn extract_chars_in_rect(
164 &self,
165 page_index: usize,
166 region: crate::geometry::Rect,
167 mode: crate::layout::RectFilterMode,
168 ) -> Result<Vec<crate::layout::TextChar>> {
169 use crate::layout::SpatialCollectionFiltering;
170 let chars = self.extract_chars(page_index)?;
171 Ok(chars.filter_by_rect(®ion, mode))
172 }
173
174 pub fn extract_images_in_rect(
176 &self,
177 page_index: usize,
178 region: crate::geometry::Rect,
179 ) -> Result<Vec<crate::extractors::PdfImage>> {
180 let images = self.extract_images(page_index)?;
181 Ok(images
182 .into_iter()
183 .filter(|img| {
184 if let Some(bbox) = img.bbox() {
185 bbox.intersects(®ion)
186 } else {
187 false
188 }
189 })
190 .collect())
191 }
192
193 pub fn get_page_info(&self, page_index: usize) -> Result<PageInfo> {
197 let page = self.get_page(page_index)?;
198 let page_dict = page.as_dict().ok_or_else(|| Error::ParseError {
199 offset: 0,
200 reason: "Page is not a dictionary".to_string(),
201 })?;
202
203 fn obj_to_f32(obj: &Object) -> Option<f32> {
204 match obj {
205 Object::Integer(i) => Some(*i as f32),
206 Object::Real(r) => Some(*r as f32),
207 _ => None,
208 }
209 }
210
211 let media_box = page_dict
218 .get("MediaBox")
219 .map(|o| self.resolve_obj_ref(o))
220 .as_ref()
221 .and_then(|o| o.as_array().map(|a| a.to_owned()))
222 .map(|arr| {
223 let r: Vec<Object> = arr.iter().map(|o| self.resolve_obj_ref(o)).collect();
224 let x0 = r.first().and_then(obj_to_f32).unwrap_or(0.0);
225 let y0 = r.get(1).and_then(obj_to_f32).unwrap_or(0.0);
226 let x1 = r.get(2).and_then(obj_to_f32).unwrap_or(612.0);
227 let y1 = r.get(3).and_then(obj_to_f32).unwrap_or(792.0);
228 crate::geometry::Rect::from_points(x0, y0, x1, y1)
229 })
230 .unwrap_or(crate::geometry::Rect::from_points(0.0, 0.0, 612.0, 792.0));
231
232 let crop_box = page_dict
233 .get("CropBox")
234 .map(|o| self.resolve_obj_ref(o))
235 .as_ref()
236 .and_then(|o| o.as_array().map(|a| a.to_owned()))
237 .map(|arr| {
238 let r: Vec<Object> = arr.iter().map(|o| self.resolve_obj_ref(o)).collect();
239 let x0 = r.first().and_then(obj_to_f32).unwrap_or(0.0);
240 let y0 = r.get(1).and_then(obj_to_f32).unwrap_or(0.0);
241 let x1 = r.get(2).and_then(obj_to_f32).unwrap_or(612.0);
242 let y1 = r.get(3).and_then(obj_to_f32).unwrap_or(792.0);
243 crate::geometry::Rect::from_points(x0, y0, x1, y1)
244 });
245
246 let rotation = page_dict
247 .get("Rotate")
248 .map(|o| self.resolve_obj_ref(o))
249 .as_ref()
250 .and_then(|o| match o {
251 Object::Integer(i) => Some(*i as i32),
252 Object::Real(r) => Some(*r as i32),
253 _ => None,
254 })
255 .unwrap_or(0);
256
257 Ok(PageInfo {
258 media_box,
259 crop_box,
260 rotation,
261 })
262 }
263
264 pub fn get_page_resources(&self, page_index: usize) -> Result<Object> {
269 let page = self.get_page(page_index)?;
270 let page_dict = page.as_dict().ok_or_else(|| Error::ParseError {
271 offset: 0,
272 reason: "Page is not a dictionary".to_string(),
273 })?;
274
275 let resources = page_dict
276 .get("Resources")
277 .cloned()
278 .unwrap_or(Object::Dictionary(std::collections::HashMap::new()));
279
280 if let Some(ref_val) = resources.as_reference() {
281 self.load_object(ref_val)
282 } else {
283 Ok(resources)
284 }
285 }
286}