Skip to content

Commit

Permalink
fixes and form example
Browse files Browse the repository at this point in the history
  • Loading branch information
s3bk committed Dec 9, 2023
1 parent dc5a911 commit cf0ed63
Show file tree
Hide file tree
Showing 4 changed files with 209 additions and 7 deletions.
140 changes: 140 additions & 0 deletions examples/src/bin/form.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
extern crate pdf;

use std::collections::HashMap;

Check warning on line 3 in examples/src/bin/form.rs

View workflow job for this annotation

GitHub Actions / clippy

unused import: `std::collections::HashMap`

warning: unused import: `std::collections::HashMap` --> examples/src/bin/form.rs:3:5 | 3 | use std::collections::HashMap; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default
use std::env::args;

use pdf::content::{FormXObject, Op, serialize_ops};
use pdf::error::PdfError;
use pdf::file::{FileOptions, Log};

Check warning on line 8 in examples/src/bin/form.rs

View workflow job for this annotation

GitHub Actions / clippy

unused import: `Log`

warning: unused import: `Log` --> examples/src/bin/form.rs:8:30 | 8 | use pdf::file::{FileOptions, Log}; | ^^^
use pdf::font::{Font, FontData, TFont};

Check warning on line 9 in examples/src/bin/form.rs

View workflow job for this annotation

GitHub Actions / clippy

unused imports: `FontData`, `Font`, `TFont`

warning: unused imports: `FontData`, `Font`, `TFont` --> examples/src/bin/form.rs:9:17 | 9 | use pdf::font::{Font, FontData, TFont}; | ^^^^ ^^^^^^^^ ^^^^^
use pdf::object::*;
use pdf::primitive::{PdfString, Primitive, Name};

Check warning on line 11 in examples/src/bin/form.rs

View workflow job for this annotation

GitHub Actions / clippy

unused import: `Name`

warning: unused import: `Name` --> examples/src/bin/form.rs:11:44 | 11 | use pdf::primitive::{PdfString, Primitive, Name}; | ^^^^

fn main() -> Result<(), PdfError> {
let path = args().nth(1).expect("no file given");
println!("read: {}", path);

let mut file = FileOptions::cached().open(&path).unwrap();
let mut to_update_field: Option<_> = None;

let page0 = file.get_page(0).unwrap();
let ops = page0

Check warning on line 21 in examples/src/bin/form.rs

View workflow job for this annotation

GitHub Actions / clippy

unused variable: `ops`

warning: unused variable: `ops` --> examples/src/bin/form.rs:21:9 | 21 | let ops = page0 | ^^^ help: if this is intentional, prefix it with an underscore: `_ops` | = note: `#[warn(unused_variables)]` on by default
.contents.as_ref().unwrap()
.operations(&file.resolver()).unwrap();

for annot in &page0.annotations {
if let Some(ref a) = annot.appearance_streams {
let normal = file.resolver().get(a.normal);
if let Ok(normal) = normal {
match *normal {
AppearanceStreamEntry::Single(ref s) => {
//dbg!(&s.stream.resources);

let mut ops = s.operations(&file.resolver())?;
for op in ops.iter_mut() {
match op {
Op::TextDraw { text } => {
println!("{}", text.to_string_lossy());
*text = PdfString::from("helloo");
}
_ => {}
}

Check warning on line 41 in examples/src/bin/form.rs

View workflow job for this annotation

GitHub Actions / clippy

you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`

warning: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> examples/src/bin/form.rs:35:29 | 35 | / ... match op { 36 | | ... Op::TextDraw { text } => { 37 | | ... println!("{}", text.to_string_lossy()); 38 | | ... *text = PdfString::from("helloo"); 39 | | ... } 40 | | ... _ => {} 41 | | ... } | |_______________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#single_match help: try | 35 ~ if let Op::TextDraw { text } = op { 36 + println!("{}", text.to_string_lossy()); 37 + *text = PdfString::from("helloo"); 38 + } |
}
let stream = Stream::new(s.stream.info.info.clone(), serialize_ops(&ops)?);

let normal2 = AppearanceStreamEntry::Single(FormXObject { stream });
file.update(a.normal.get_inner(), normal2)?;
}
_ => {}
}

Check warning on line 49 in examples/src/bin/form.rs

View workflow job for this annotation

GitHub Actions / clippy

you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`

warning: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> examples/src/bin/form.rs:29:17 | 29 | / match *normal { 30 | | AppearanceStreamEntry::Single(ref s) => { 31 | | //dbg!(&s.stream.resources); 32 | | ... | 48 | | _ => {} 49 | | } | |_________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#single_match = note: `#[warn(clippy::single_match)]` on by default help: try | 29 ~ if let AppearanceStreamEntry::Single(ref s) = *normal { 30 + //dbg!(&s.stream.resources); 31 + 32 + let mut ops = s.operations(&file.resolver())?; 33 + for op in ops.iter_mut() { 34 + match op { 35 + Op::TextDraw { text } => { 36 + println!("{}", text.to_string_lossy()); 37 + *text = PdfString::from("helloo"); 38 + } 39 + _ => {} 40 + } 41 + } 42 + let stream = Stream::new(s.stream.info.info.clone(), serialize_ops(&ops)?); 43 + 44 + let normal2 = AppearanceStreamEntry::Single(FormXObject { stream }); 45 + file.update(a.normal.get_inner(), normal2)?; 46 + } |
}
}
}

if let Some(ref forms) = file.get_root().forms {
println!("Forms:");
for field in forms.fields.iter().take(1) {
print!(" {:?} = ", field.name);
match field.value {
Primitive::String(ref s) => println!("{}", s.to_string_lossy()),
Primitive::Integer(i) => println!("{}", i),
Primitive::Name(ref s) => println!("{}", s),
ref p => println!("{:?}", p),
}

if to_update_field.is_none() {
to_update_field = Some(field.clone());
}
}
}

/*
let font = Font {
data: FontData::TrueType(TFont{
base_font: Some(Name::from("Helvetica")),
first_char: None,
font_descriptor: None,
last_char: None,
widths: None,
}),
encoding: Some(pdf::encoding::Encoding::standard()),
name: None,
subtype: pdf::font::FontType::TrueType,
to_unicode: None,
_other: Default::default()
};
let font_name = Name::from("Helvetica");
let font = file.create(font)?;
let mut fonts = HashMap::new();
fonts.insert("Helvetica".into(), font.into());
let resources = Resources {
fonts,
.. Default::default()
};
let resources = file.create(resources)?;
*/

if let Some(to_update_field) = to_update_field {
println!("\nUpdating field:");
println!("{:?}\n", to_update_field);

let text = "helloo";
let new_value: PdfString = PdfString::new(text.into());
let mut updated_field = (*to_update_field).clone();
updated_field.value = Primitive::String(new_value);

/*
let mut form_dict = FormDict {
bbox: updated_field.rect,
resources: Some(resources.into()),
.. Default::default()
};
let content = format!("q BT /Helvetica 14 Tf ({text}) ET Q");
let form = FormXObject {
stream: Stream::new(form_dict, content.into_bytes())
};
//dbg!(&form);
let normal = AppearanceStreamEntry::Single(form);
let apperance = AppearanceStreams {
normal: file.create(normal)?.into(),
down: None,
rollover: None
};
//updated_field.appearance_streams = Some(apperance.into());
//updated_field.appearance_state = Some("N".into());
//dbg!(&updated_field);
*/
let reference = file.update(

Check warning on line 128 in examples/src/bin/form.rs

View workflow job for this annotation

GitHub Actions / clippy

unused variable: `reference`

warning: unused variable: `reference` --> examples/src/bin/form.rs:128:13 | 128 | let reference = file.update( | ^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_reference`
to_update_field.get_ref().get_inner(),
updated_field,
)?;

file.save_to("output/out.pdf")?;

println!("\nUpdated field:");
//println!("{:?}\n", reference);
}

Ok(())
}
5 changes: 3 additions & 2 deletions pdf/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ impl CatalogBuilder {
lgi: page.lgi,
vp: page.vp,
other: page.other,
annotations: vec![]
};
update.fulfill(promise, PagesNode::Leaf(page))?;
}
Expand All @@ -157,8 +158,8 @@ pub struct PdfBuilder<SC, OC, L> {
}
impl<SC, OC, L> PdfBuilder<SC, OC, L>
where
SC: Cache<Result<AnySync, Arc<PdfError>>> + Default,
OC: Cache<Result<Arc<[u8]>, Arc<PdfError>>> + Default,
SC: Cache<Result<AnySync, Arc<PdfError>>>,
OC: Cache<Result<Arc<[u8]>, Arc<PdfError>>>,
L: Log,
{
pub fn new(fileoptions: FileOptions<'_, SC, OC, L>) -> Self {
Expand Down
2 changes: 1 addition & 1 deletion pdf/src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ where
fn update<T: ObjectWrite>(&mut self, old: PlainRef, obj: T) -> Result<RcRef<T>> {
let r = match self.refs.get(old.id)? {
XRef::Free { .. } => panic!(),
XRef::Raw { gen_nr, .. } => PlainRef { id: old.id, gen: gen_nr + 1 },
XRef::Raw { gen_nr, .. } => PlainRef { id: old.id, gen: gen_nr },
XRef::Stream { .. } => return self.create(obj),
XRef::Promised => PlainRef { id: old.id, gen: 0 },
XRef::Invalid => panic!()
Expand Down
69 changes: 65 additions & 4 deletions pdf/src/object/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,20 @@ impl PageRc {
self.0.get_ref()
}
}
impl Object for PageRc {
fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<PageRc> {
let node = t!(RcRef::from_primitive(p, resolve));
match *node {
PagesNode::Tree(_) => Err(PdfError::WrongDictionaryType {expected: "Page".into(), found: "Pages".into()}),
PagesNode::Leaf(_) => Ok(PageRc(node))
}
}
}
impl ObjectWrite for PageRc {
fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
self.0.to_primitive(update)
}
}

/// A `PagesNode::Tree` wrapped in a `RcRef`
///
Expand Down Expand Up @@ -278,6 +292,9 @@ pub struct Page {
#[pdf(key="VP")]
pub vp: Option<Primitive>,

#[pdf(key="Annots", default="vec![]")]
pub annotations: Vec<Annot>,

#[pdf(other)]
pub other: Dictionary,
}
Expand Down Expand Up @@ -307,6 +324,7 @@ impl Page {
lgi: None,
vp: None,
other: Dictionary::new(),
annotations: vec![]
}
}
pub fn media_box(&self) -> Result<Rect> {
Expand Down Expand Up @@ -335,6 +353,7 @@ impl Page {
}
impl SubType<PagesNode> for Page {}


#[derive(Object, DataSize)]
pub struct PageLabel {
#[pdf(key="S")]
Expand Down Expand Up @@ -764,7 +783,6 @@ impl RenderingIntent {
}
}


#[derive(Object, Debug, DataSize, DeepClone, ObjectWrite, Clone, Default)]
#[pdf(Type="XObject?", Subtype="Form")]
pub struct FormDict {
Expand Down Expand Up @@ -924,6 +942,41 @@ pub struct SignatureReferenceDictionary {
pub other: Dictionary
}


#[derive(Object, ObjectWrite, Debug, Clone, DataSize)]
#[pdf(Type="Annot?")]
pub struct Annot {
#[pdf(key="Subtype")]
pub subtype: Name,

#[pdf(key="Rect")]
pub rect: Rect,

#[pdf(key="Contents")]
pub contents: Option<PdfString>,

#[pdf(key="P")]
pub page: Option<PageRc>,

#[pdf(key="NM")]
pub annotation_name: Option<PdfString>,

#[pdf(key="M")]
pub date: Option<Date>,

#[pdf(key="F", default="0")]
pub annot_flags: u32,

#[pdf(key="AP")]
pub appearance_streams: Option<MaybeRef<AppearanceStreams>>,

#[pdf(key="AS")]
pub appearance_state: Option<Name>,

#[pdf(key="Border")]
pub border: Option<Primitive>,
}

#[derive(Object, ObjectWrite, Debug, DataSize, Clone)]
pub struct FieldDictionary {
#[pdf(key="FT")]
Expand Down Expand Up @@ -956,15 +1009,23 @@ pub struct FieldDictionary {
#[pdf(key="DV")]
pub default_value: Primitive,

#[pdf(key="DR")]
pub default_resources: Option<MaybeRef<Resources>>,

#[pdf(key="AA")]
pub actions: Option<Dictionary>,

#[pdf(key="AP")]
pub appearance_streams: Option<MaybeRef<AppearanceStreams>>,

#[pdf(key="Rect")]
pub rect: Rect,

#[pdf(key="MaxLen")]
pub max_len: Option<u32>,



#[pdf(key="Subtype")]
pub subtype: Name,

#[pdf(other)]
pub other: Dictionary
}
Expand Down

0 comments on commit cf0ed63

Please sign in to comment.