mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-03 06:51:50 -06:00
refactor(engine): drop redundant image and font checks
- page_image_at: PageImage::contains already requires the point inside visible_rect (rect clipped by the placement clip), so the extra bounds test before it decided nothing. - image_dimensions: the 256 MB input-length guard repeated the caller's; the decoder's max_alloc limit still caps what decoding allocates. Its test no longer allocates 256 MB to hit that guard. - font_content_key hashed every font file twice; one 64-bit hash plus the length is enough to tell duplicate files apart. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
4c70761803
commit
3817a9f3ec
@@ -18,16 +18,8 @@ impl Document {
|
||||
/// [`Document::page_images`]: a raster image, or Form artwork that holds one.
|
||||
pub fn page_image_at(&self, page: usize, at: [f64; 2]) -> Option<usize> {
|
||||
let editor = self.editor.as_ref()?;
|
||||
let inside = |r: &[f64; 4]| (r[0]..=r[2]).contains(&at[0]) && (r[1]..=r[3]).contains(&at[1]);
|
||||
self.page_images(page).iter().rposition(|i| {
|
||||
let bounds = if let Some(clip) = i.clip_rect {
|
||||
let r = [i.rect[0].max(clip[0]), i.rect[1].max(clip[1]), i.rect[2].min(clip[2]), i.rect[3].min(clip[3])];
|
||||
if r.iter().all(|v| v.is_finite()) && r[2] > r[0] && r[3] > r[1] { r } else { i.visible_rect.unwrap_or(i.rect) }
|
||||
} else {
|
||||
i.visible_rect.unwrap_or(i.rect)
|
||||
};
|
||||
inside(&bounds)
|
||||
&& i.contains(at)
|
||||
i.contains(at)
|
||||
&& match (i.is_form, i.object) {
|
||||
(false, Some(_)) => true,
|
||||
(true, Some(form)) => picture_in_form(&editor.cos, form).is_some(),
|
||||
|
||||
@@ -62,9 +62,6 @@ pub(crate) fn mark_source(doc: &mut pdfcraft_cos::Document, f: &MarkFile) -> Res
|
||||
|
||||
/// The dimensions of an image from its bytes (JPEG, PNG, TIFF), without decoding the full raster.
|
||||
pub fn image_dimensions(bytes: &[u8]) -> Option<(u32, u32)> {
|
||||
if bytes.len() > 64_000_000 * 4 {
|
||||
return None;
|
||||
}
|
||||
let format = image::guess_format(bytes).ok()?;
|
||||
let mut reader = image::ImageReader::with_format(std::io::Cursor::new(bytes), format);
|
||||
let mut limits = image::Limits::default();
|
||||
@@ -123,11 +120,8 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_and_oversized_inputs_return_none() {
|
||||
fn invalid_inputs_return_none() {
|
||||
assert_eq!(image_dimensions(&[]), None);
|
||||
assert_eq!(image_dimensions(b"not an image"), None);
|
||||
|
||||
let huge = vec![0u8; 64_000_000 * 4 + 1];
|
||||
assert_eq!(image_dimensions(&huge), None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,14 +89,11 @@ pub fn discover_budgeted(roots: &[PathBuf], mut budget: u64) -> Vec<FontFile> {
|
||||
files
|
||||
}
|
||||
|
||||
fn font_content_key(bytes: &[u8]) -> (usize, u64, u64) {
|
||||
fn font_content_key(bytes: &[u8]) -> (usize, u64) {
|
||||
use std::hash::{DefaultHasher, Hasher};
|
||||
let mut h1 = DefaultHasher::new();
|
||||
h1.write(bytes);
|
||||
let mut h2 = DefaultHasher::new();
|
||||
h2.write_u8(0xff);
|
||||
h2.write(bytes);
|
||||
(bytes.len(), h1.finish(), h2.finish())
|
||||
let mut h = DefaultHasher::new();
|
||||
h.write(bytes);
|
||||
(bytes.len(), h.finish())
|
||||
}
|
||||
fn font_extension(path: &Path) -> bool {
|
||||
path.extension().and_then(std::ffi::OsStr::to_str).is_some_and(|e| e.eq_ignore_ascii_case("ttf") || e.eq_ignore_ascii_case("otf"))
|
||||
|
||||
Reference in New Issue
Block a user