Skip to content

Commit

Permalink
improve file modification
Browse files Browse the repository at this point in the history
  • Loading branch information
s3bk committed Oct 30, 2023
1 parent 994b984 commit a4ba26b
Show file tree
Hide file tree
Showing 17 changed files with 782 additions and 89 deletions.
15 changes: 15 additions & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "pdf-examples"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
pdf = { path = "../pdf" }
datasize = "0.2.13"
clap = { version = "*", features = ["derive"] }
image = "*"

[[bin]]
name = "extract_page"
94 changes: 94 additions & 0 deletions examples/src/bin/add_image.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use std::{path::PathBuf, io::BufReader, fs::File, error::Error};

use pdf::{
error::PdfError,
file::FileOptions,
object::*,
build::*,
primitive::{PdfString, Name}, enc::{StreamFilter, DCTDecodeParams}, content::{Op, Matrix, Content},
};

use clap::Parser;
use std::io::Cursor;
use image::io::Reader as ImageReader;

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
/// Input file
#[arg(short, long)]
input: PathBuf,

/// Page number
#[arg(long)]
image: PathBuf,

/// Page number to add the image to
#[arg(short, long, default_value_t = 0)]
page: u32,

/// Output file
#[arg(short, long)]
output: PathBuf,
}

struct Point {
x: f32,
y: f32
}

fn main() -> Result<(), Box<dyn Error>> {
let args = Args::parse();

let img_data = std::fs::read(&args.image)?;
let img = ImageReader::new(Cursor::new(&img_data)).with_guessed_format()?.decode()?;
let image_dict = ImageDict {
width: img.width(),
height: img.height(),
color_space: Some(ColorSpace::DeviceRGB),
bits_per_component: Some(8),
.. Default::default()
};
let image = Stream::new_with_filters(image_dict, img_data, vec![StreamFilter::DCTDecode(DCTDecodeParams { color_transform: None})]);

let mut file = FileOptions::cached().open(&args.input).unwrap();
let page = file.get_page(args.page).expect("no such page");

let resources = page.resources()?;
let mut resources2: Resources = (**resources).clone();

let image_obj = XObject::Image(ImageXObject { inner: image });
let image_ref = file.create(image_obj)?;

// assume that name did not exist
let image_name = Name::from("MyImage");
resources2.xobjects.insert(image_name.clone(), image_ref.get_ref());


let mut ops = page.contents.as_ref().unwrap().operations(&file.resolver())?;

let scale = Point { x: img.width() as f32, y: img.height() as f32 };
let skew = Point { x: 0.0, y: 0.0 };
let position = Point { x: 100., y: 100. };

ops.append(&mut vec![
Op::Save, // ADD IMAGE START
Op::Transform { matrix: Matrix{ // IMAGE MANIPULATION
a: scale.x * 0.1, d: scale.y * 0.1,
b: skew.x, c: skew.y,
e: position.x, f: position.y,
} },
Op::XObject {name: image_name}, // IMAGE
Op::Restore, // ADD IMAGE STOP
]);

let mut page2: Page = (*page).clone();
page2.contents = Some(Content::from_ops(ops));
page2.resources = Some(file.create(resources2)?.into());

file.update(page.get_ref().get_inner(), page2)?;

file.save_to(&args.output)?;

Ok(())
}
54 changes: 54 additions & 0 deletions examples/src/bin/extract_page.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use std::path::PathBuf;

use pdf::{
error::PdfError,
file::FileOptions,
object::*,
build::*,
primitive::PdfString,
};

use clap::Parser;

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
/// Input file
#[arg(short, long)]
input: PathBuf,

/// Page number
#[arg(short, long, default_value_t = 0)]
page: u32,

/// Output file
#[arg(short, long)]
output: PathBuf,
}

fn main() -> Result<(), PdfError> {
let args = Args::parse();

let old_file = FileOptions::cached().open(&args.input).unwrap();
let old_page = old_file.get_page(args.page).expect("no such page");

let mut builder = PdfBuilder::new(FileOptions::cached());

let mut importer = Importer::new(old_file.resolver(), &mut builder.storage);
let mut pages = Vec::new();

let new_page = PageBuilder::clone_page(&old_page, &mut importer)?;

pages.push(new_page);

let catalog = CatalogBuilder::from_pages(pages);

let mut info = InfoDict::default();
info.title = Some(PdfString::from("test"));

let data = builder.info(info).build(catalog)?;

std::fs::write(&args.output, data)?;

Ok(())
}
65 changes: 44 additions & 21 deletions pdf/src/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,32 @@ pub trait AnyObject {
fn type_id(&self) -> TypeId;
fn size(&self) -> usize;
}
impl<T> AnyObject for T
where T: Object + 'static + DataSize
{

#[repr(transparent)]
pub struct NoSize<T>(T);
impl<T: 'static> AnyObject for NoSize<T> {
fn size(&self) -> usize {
0
}
fn type_id(&self) -> TypeId {
TypeId::of::<T>()
}
fn type_name(&self) -> &'static str {
std::any::type_name::<T>()
}
}

#[repr(transparent)]
pub struct WithSize<T>(T);
impl<T: DataSize + 'static> AnyObject for WithSize<T> {
fn size(&self) -> usize {
datasize::data_size(&self.0)
}
fn type_id(&self) -> TypeId {
TypeId::of::<T>()
}
fn size(&self) -> usize {
datasize::data_size(self)
fn type_name(&self) -> &'static str {
std::any::type_name::<T>()
}
}

Expand All @@ -41,19 +56,23 @@ impl Any {
}
}
pub fn new<T>(rc: Rc<T>) -> Any
where T: AnyObject + 'static
where WithSize<T>: AnyObject, T: 'static
{
Any(rc as _)
Any(unsafe {
std::mem::transmute::<Rc<T>, Rc<WithSize<T>>>(rc)
} as _)
}
pub fn new_without_size<T>(rc: Rc<T>) -> Any
where NoSize<T>: AnyObject, T: 'static
{
Any(unsafe {
std::mem::transmute::<Rc<T>, Rc<NoSize<T>>>(rc)
} as _)
}
pub fn type_name(&self) -> &'static str {
self.0.type_name()
}
}
impl<T: AnyObject + 'static> From<Rc<T>> for Any {
fn from(t: Rc<T>) -> Self {
Any::new(t)
}
}

#[derive(Clone, DataSize)]
pub struct AnySync(Arc<dyn AnyObject+Sync+Send>);
Expand All @@ -68,7 +87,7 @@ impl globalcache::ValueSize for AnySync {

impl AnySync {
pub fn downcast<T>(self) -> Result<Arc<T>>
where T: AnyObject + Sync + Send + 'static
where T: 'static
{
if TypeId::of::<T>() == self.0.type_id() {
unsafe {
Expand All @@ -80,19 +99,23 @@ impl AnySync {
}
}
pub fn new<T>(arc: Arc<T>) -> AnySync
where T: AnyObject + Sync + Send + 'static
where WithSize<T>: AnyObject, T: Sync + Send + 'static
{
AnySync(unsafe {
std::mem::transmute::<Arc<T>, Arc<WithSize<T>>>(arc)
} as _)
}
pub fn new_without_size<T>(arc: Arc<T>) -> AnySync
where NoSize<T>: AnyObject, T: Sync + Send + 'static
{
AnySync(arc as _)
AnySync(unsafe {
std::mem::transmute::<Arc<T>, Arc<NoSize<T>>>(arc)
} as _)
}
pub fn type_name(&self) -> &'static str {
self.0.type_name()
}
}
impl<T: AnyObject + Sync + Send + 'static> From<Arc<T>> for AnySync {
fn from(t: Arc<T>) -> Self {
AnySync::new(t)
}
}
fn type_mismatch<T: AnyObject + 'static>(name: &str) -> PdfError {
fn type_mismatch<T>(name: &str) -> PdfError {
PdfError::Other { msg: format!("expected {}, found {}", std::any::type_name::<T>(), name) }
}
Loading

0 comments on commit a4ba26b

Please sign in to comment.