pdfrum_anyrender/
sources.rs1use crate::run_text::RunTexts;
5use std::collections::HashMap;
6use std::fmt;
7use std::sync::Arc;
8
9#[derive(Debug, Default)]
11pub struct Sources {
12 pub texts: RunTexts,
14 pub images: ImageSources,
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20pub enum ImageCodec {
21 Jpeg,
23 Png,
25}
26
27impl ImageCodec {
28 pub fn sniff(bytes: &[u8]) -> Option<Self> {
31 match bytes {
32 [0xFF, 0xD8, 0xFF, ..] => Some(ImageCodec::Jpeg),
33 [0x89, b'P', b'N', b'G', b'\r', b'\n', 0x1A, b'\n', ..] => Some(ImageCodec::Png),
34 _ => None,
35 }
36 }
37}
38
39#[derive(Clone)]
41pub struct EncodedImage {
42 codec: ImageCodec,
43 bytes: Arc<Vec<u8>>,
44}
45
46impl EncodedImage {
47 pub fn sniffed(bytes: Vec<u8>) -> Option<Self> {
49 let codec = ImageCodec::sniff(&bytes)?;
50 Some(EncodedImage {
51 codec,
52 bytes: Arc::new(bytes),
53 })
54 }
55
56 pub fn codec(&self) -> ImageCodec {
58 self.codec
59 }
60
61 pub fn bytes(&self) -> &Arc<Vec<u8>> {
63 &self.bytes
64 }
65}
66
67impl fmt::Debug for EncodedImage {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 f.debug_struct("EncodedImage")
70 .field("codec", &self.codec)
71 .field("len", &self.bytes.len())
72 .finish()
73 }
74}
75
76#[derive(Debug, Default)]
80pub struct ImageSources {
81 by_blob: HashMap<u64, EncodedImage>,
82}
83
84impl ImageSources {
85 pub fn insert(&mut self, blob: u64, source: EncodedImage) {
87 self.by_blob.insert(blob, source);
88 }
89
90 pub fn get(&self, blob: u64) -> Option<&EncodedImage> {
92 self.by_blob.get(&blob)
93 }
94
95 pub fn len(&self) -> usize {
97 self.by_blob.len()
98 }
99
100 pub fn is_empty(&self) -> bool {
102 self.by_blob.is_empty()
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::ImageCodec;
109
110 const CASES: &[(&[u8], Option<ImageCodec>)] = &[
111 (&[0xFF, 0xD8, 0xFF, 0xE0], Some(ImageCodec::Jpeg)),
112 (b"\x89PNG\r\n\x1a\nrest", Some(ImageCodec::Png)),
113 (b"GIF89a", None),
114 (b"", None),
115 ];
116
117 #[test]
118 fn codecs_are_sniffed_by_signature() {
119 for &(bytes, want) in CASES {
120 assert_eq!(ImageCodec::sniff(bytes), want, "{bytes:?}");
121 }
122 }
123}