use crate::objects::tree::{deref, ref_id};
use lopdf::{Document, Object, ObjectId};
pub fn extract_font_bytes(doc: &Document, page_id: ObjectId, font_name: &[u8]) -> Option<Vec<u8>> {
let page = doc.get_object(page_id).ok()?;
let page_dict = page.as_dict().ok()?;
let res_val = page_dict.get(b"Resources").ok()?;
let res_dict = deref(doc, res_val).as_dict().ok()?;
let font_val = res_dict.get(b"Font").ok()?;
let font_dict = deref(doc, font_val).as_dict().ok()?;
let font_val = font_dict.get(font_name).ok()?;
let font_id = ref_id(font_val)?;
let font_obj = doc.get_object(font_id).ok()?;
let font_inner = font_obj.as_dict().ok()?;
let descriptor_dict = if let Ok(Object::Array(arr)) = font_inner.get(b"DescendantFonts") {
let desc_ref = arr.first()?;
let desc_id = ref_id(desc_ref)?;
let desc_obj = doc.get_object(desc_id).ok()?;
let desc_dict = desc_obj.as_dict().ok()?;
let fd_val = desc_dict.get(b"FontDescriptor").ok()?;
let fd_id = ref_id(fd_val)?;
let fd_obj = doc.get_object(fd_id).ok()?;
fd_obj.as_dict().ok()?.clone()
} else {
let fd_val = font_inner.get(b"FontDescriptor").ok()?;
let fd_id = ref_id(fd_val)?;
let fd_obj = doc.get_object(fd_id).ok()?;
fd_obj.as_dict().ok()?.clone()
};
let file_val = descriptor_dict
.get(b"FontFile2")
.or_else(|_| descriptor_dict.get(b"FontFile3"))
.ok()?;
let file_id = ref_id(file_val)?;
let file_obj = doc.get_object(file_id).ok()?;
if let Object::Stream(s) = file_obj {
let raw = s.decompressed_content().ok()?;
Some(wrap_cff_in_otf(raw))
} else {
None
}
}
fn wrap_cff_in_otf(mut bytes: Vec<u8>) -> Vec<u8> {
if bytes.len() < 4 {
return bytes;
}
let sig = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
match sig {
0x0001_0000 | 0x4F54_544F | 0x7472_7565 | 0x7479_7031 | 0x774F_4646 | 0x774F_4632 => return bytes,
_ => {}
}
if bytes[0] != 1 && bytes[0] != 2 {
return bytes;
}
let cff_len = bytes.len() as u32;
let data_offset: u32 = 12 + 16;
let mut otf: Vec<u8> = Vec::with_capacity(data_offset as usize + bytes.len());
otf.extend_from_slice(b"OTTO"); otf.extend_from_slice(&1u16.to_be_bytes()); otf.extend_from_slice(&16u16.to_be_bytes()); otf.extend_from_slice(&0u16.to_be_bytes()); otf.extend_from_slice(&0u16.to_be_bytes());
otf.extend_from_slice(b"CFF "); otf.extend_from_slice(&0u32.to_be_bytes()); otf.extend_from_slice(&data_offset.to_be_bytes()); otf.extend_from_slice(&cff_len.to_be_bytes());
otf.append(&mut bytes);
otf
}