WIP adding rendering
This commit is contained in:
parent
aba6368948
commit
9445599850
10 changed files with 2271 additions and 147 deletions
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
pdf::{
|
||||
PdfObjects,
|
||||
PdfObjectAndParseCache, PdfObjects,
|
||||
parse::{
|
||||
GetPdfInputPosition, PdfInputPosition, PdfInputPositionNoCompare, PdfParse,
|
||||
PdfParseError,
|
||||
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
stream_filters::PdfStreamFilter,
|
||||
},
|
||||
pdf_parse,
|
||||
util::ArcOrRef,
|
||||
util::{ArcOrRef, DagDebugState},
|
||||
};
|
||||
use std::{
|
||||
any::TypeId,
|
||||
|
|
@ -892,17 +892,35 @@ impl PdfObjectIndirect {
|
|||
final_id: Arc::new(OnceLock::new()),
|
||||
}
|
||||
}
|
||||
pub fn get(&self) -> PdfObjectDirect {
|
||||
let Some(objects) = self.objects.upgrade() else {
|
||||
panic!("PdfObjects is no longer available");
|
||||
};
|
||||
pub(crate) fn cache_parse<T: 'static + Send + Sync, E>(
|
||||
&self,
|
||||
parse_inner: impl FnOnce(PdfObjectDirect) -> Result<Arc<T>, E>,
|
||||
) -> Result<Arc<T>, E> {
|
||||
self.get_object_and_parse_cache(|object, object_and_parse_cache| {
|
||||
match object_and_parse_cache {
|
||||
Some(object_and_parse_cache) => {
|
||||
if let Some(retval) = object_and_parse_cache.parse_cache_get::<T>() {
|
||||
println!("cache reused for {object:?}");
|
||||
return Ok(retval);
|
||||
}
|
||||
parse_inner(object)
|
||||
.map(|retval| object_and_parse_cache.parse_cache_get_or_insert::<T>(retval))
|
||||
}
|
||||
None => parse_inner(object),
|
||||
}
|
||||
})
|
||||
}
|
||||
fn get_object_and_parse_cache_inner<'a>(
|
||||
&self,
|
||||
objects: &'a PdfObjects,
|
||||
) -> (PdfObjectDirect, Option<&'a PdfObjectAndParseCache>) {
|
||||
if let Some(objects) = objects.inner.get() {
|
||||
let final_id = self.final_id.get().copied();
|
||||
let limit = if final_id.is_some() { 1 } else { 1000usize };
|
||||
let mut id = final_id.unwrap_or(self.id);
|
||||
for _ in 0..limit {
|
||||
if let Some(object) = objects.objects.get(&self.id) {
|
||||
let retval = match object {
|
||||
if let Some(object_and_parse_cache) = objects.objects.get(&self.id) {
|
||||
let object = match &object_and_parse_cache.object {
|
||||
PdfObject::Boolean(v) => PdfObjectDirect::Boolean(*v),
|
||||
PdfObject::Integer(v) => PdfObjectDirect::Integer(*v),
|
||||
PdfObject::Real(v) => PdfObjectDirect::Real(*v),
|
||||
|
|
@ -919,13 +937,26 @@ impl PdfObjectIndirect {
|
|||
};
|
||||
// we could be racing with another thread, so set can fail but that's not a problem
|
||||
let _ = self.final_id.set(id);
|
||||
return retval;
|
||||
return (object, Some(object_and_parse_cache));
|
||||
} else {
|
||||
return PdfObjectDirect::Null(PdfNull::new(id.pos));
|
||||
return (PdfNull::new(id.pos).into(), None);
|
||||
}
|
||||
}
|
||||
}
|
||||
PdfObjectDirect::Null(PdfNull::new(self.pos()))
|
||||
(PdfNull::new(self.pos()).into(), None)
|
||||
}
|
||||
fn get_object_and_parse_cache<R>(
|
||||
&self,
|
||||
f: impl FnOnce(PdfObjectDirect, Option<&PdfObjectAndParseCache>) -> R,
|
||||
) -> R {
|
||||
let Some(objects) = self.objects.upgrade() else {
|
||||
panic!("PdfObjects is no longer available");
|
||||
};
|
||||
let (object, object_and_parse_cache) = self.get_object_and_parse_cache_inner(&objects);
|
||||
f(object, object_and_parse_cache)
|
||||
}
|
||||
pub fn get(&self) -> PdfObjectDirect {
|
||||
self.get_object_and_parse_cache(|object, _object_and_parse_cache| object)
|
||||
}
|
||||
pub fn id(&self) -> PdfObjectIdentifier {
|
||||
self.id
|
||||
|
|
@ -1067,9 +1098,17 @@ impl<'a, T> IntoIterator for &'a PdfDictionary<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug> fmt::Debug for PdfDictionary<T> {
|
||||
impl<T: fmt::Debug + 'static> fmt::Debug for PdfDictionary<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_map().entries(self).finish()
|
||||
DagDebugState::scope(|state| {
|
||||
state
|
||||
.debug_or_id_with(
|
||||
&self.fields,
|
||||
|_, f| f.debug_map().entries(self).finish(),
|
||||
|f| f.write_str("{...}"),
|
||||
)
|
||||
.fmt(f)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1364,6 +1403,31 @@ pub struct PdfMatrix {
|
|||
pub elements: [f32; 6],
|
||||
}
|
||||
|
||||
impl PdfMatrix {
|
||||
pub fn identity(pos: impl Into<PdfInputPositionNoCompare>) -> Self {
|
||||
Self {
|
||||
pos: pos.into(),
|
||||
elements: [1.0, 0.0, 0.0, 1.0, 0.0, 0.0],
|
||||
}
|
||||
}
|
||||
#[must_use]
|
||||
pub fn mul(self, other: PdfMatrix, new_pos: impl Into<PdfInputPositionNoCompare>) -> Self {
|
||||
let [la, lb, lc, ld, le, lf] = self.elements;
|
||||
let [ra, rb, rc, rd, re, rf] = other.elements;
|
||||
Self {
|
||||
pos: new_pos.into(),
|
||||
elements: [
|
||||
lb * rc + la * ra,
|
||||
lb * rd + la * rb,
|
||||
ld * rc + lc * ra,
|
||||
ld * rd + lc * rb,
|
||||
re + lf * rc + le * ra,
|
||||
rf + lf * rd + le * rb,
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PdfMatrix {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self { pos, elements } = *self;
|
||||
|
|
@ -1582,7 +1646,7 @@ impl PdfParse for PdfFileSpecification {
|
|||
|
||||
pdf_parse! {
|
||||
#[pdf]
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone)]
|
||||
pub struct PdfStreamDictionary<Rest = PdfDictionary> {
|
||||
#[pdf(name = "Length")]
|
||||
pub len: usize,
|
||||
|
|
@ -1603,6 +1667,33 @@ pdf_parse! {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Rest: fmt::Debug> fmt::Debug for PdfStreamDictionary<Rest> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
DagDebugState::scope(|_state| {
|
||||
let Self {
|
||||
len,
|
||||
filters,
|
||||
decode_parms,
|
||||
file,
|
||||
file_filters,
|
||||
file_decode_parms,
|
||||
decoded_len,
|
||||
rest,
|
||||
} = self;
|
||||
f.debug_struct("PdfStreamDictionary")
|
||||
.field("len", len)
|
||||
.field("filters", filters)
|
||||
.field("decode_parms", decode_parms)
|
||||
.field("file", file)
|
||||
.field("file_filters", file_filters)
|
||||
.field("file_decode_parms", file_decode_parms)
|
||||
.field("decoded_len", decoded_len)
|
||||
.field("rest", rest)
|
||||
.finish()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct PdfStreamDictionaryFiltersAndParms<'a> {
|
||||
filters: std::iter::Enumerate<std::slice::Iter<'a, PdfStreamFilter>>,
|
||||
|
|
@ -1697,23 +1788,6 @@ impl<Rest> PdfStreamDictionary<Rest> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct UnparsedPdfStreamDictionary<Rest> {
|
||||
unparsed_dictionary: PdfDictionary,
|
||||
dictionary: Arc<OnceLock<PdfStreamDictionary<Rest>>>,
|
||||
}
|
||||
|
||||
impl<Rest: PdfParse> UnparsedPdfStreamDictionary<Rest> {
|
||||
pub(crate) fn finish_parsing(self) -> Result<(), PdfParseError> {
|
||||
let Ok(()) = self
|
||||
.dictionary
|
||||
.set(PdfParse::parse(self.unparsed_dictionary.into())?)
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PdfStreamContents: Sized + fmt::Debug + 'static {
|
||||
fn parse(
|
||||
data: &[u8],
|
||||
|
|
@ -1786,34 +1860,45 @@ impl fmt::Display for DumpBytes<'_> {
|
|||
|
||||
impl<Rest: fmt::Debug, Data: PdfStreamContents> fmt::Debug for PdfStream<Rest, Data> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self {
|
||||
pos,
|
||||
objects: _,
|
||||
dictionary,
|
||||
encoded_data,
|
||||
decoded_data,
|
||||
} = self;
|
||||
let mut debug_struct = f.debug_struct("PdfStream");
|
||||
debug_struct.field("pos", pos);
|
||||
debug_struct.field("dictionary", dictionary);
|
||||
debug_struct.field("encoded_data", &DumpBytes(encoded_data));
|
||||
if let Some(decoded_data) = decoded_data.get() {
|
||||
match decoded_data {
|
||||
Ok(decoded_data) => {
|
||||
if let Some(decoded_data) =
|
||||
<dyn std::any::Any>::downcast_ref::<Arc<[u8]>>(decoded_data)
|
||||
{
|
||||
debug_struct.field("decoded_data", &DumpBytes(&**decoded_data))
|
||||
} else {
|
||||
debug_struct.field("decoded_data", decoded_data)
|
||||
}
|
||||
}
|
||||
Err(e) => debug_struct.field("decoded_data", &Err::<(), _>(e)),
|
||||
};
|
||||
} else {
|
||||
debug_struct.field("decoded_data", &format_args!("<not-yet-decoded>"));
|
||||
}
|
||||
debug_struct.finish()
|
||||
DagDebugState::scope(|state| {
|
||||
state
|
||||
.debug_or_id_with(
|
||||
&self.decoded_data,
|
||||
|_, f| {
|
||||
let Self {
|
||||
pos,
|
||||
objects: _,
|
||||
dictionary,
|
||||
encoded_data,
|
||||
decoded_data,
|
||||
} = self;
|
||||
let mut debug_struct = f.debug_struct("PdfStream");
|
||||
debug_struct.field("pos", pos);
|
||||
debug_struct.field("dictionary", dictionary);
|
||||
debug_struct.field("encoded_data", &DumpBytes(encoded_data));
|
||||
if let Some(decoded_data) = decoded_data.get() {
|
||||
match decoded_data {
|
||||
Ok(decoded_data) => {
|
||||
if let Some(decoded_data) =
|
||||
<dyn std::any::Any>::downcast_ref::<Arc<[u8]>>(decoded_data)
|
||||
{
|
||||
debug_struct
|
||||
.field("decoded_data", &DumpBytes(&**decoded_data))
|
||||
} else {
|
||||
debug_struct.field("decoded_data", decoded_data)
|
||||
}
|
||||
}
|
||||
Err(e) => debug_struct.field("decoded_data", &Err::<(), _>(e)),
|
||||
};
|
||||
} else {
|
||||
debug_struct.field("decoded_data", &format_args!("<not-yet-decoded>"));
|
||||
}
|
||||
debug_struct.finish()
|
||||
},
|
||||
|f| f.write_str("PdfStream(...)"),
|
||||
)
|
||||
.fmt(f)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1957,7 +2042,7 @@ pdf_parse! {
|
|||
|
||||
pdf_parse! {
|
||||
#[pdf]
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone)]
|
||||
pub struct PdfObjectStreamDictionary {
|
||||
#[pdf(name = Self::TYPE_NAME)]
|
||||
pub ty: PdfObjectStreamType,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue