use crate::error::*;
pub mod lowlevel;
use lowlevel::*;
use std::borrow::Cow;
use std::collections::HashMap;
use std::fs::File;
use std::io::{self, Read};
use std::path::Path;
use url::Url;
pub struct PdfOutput<'a> {
data: &'a [u8],
_converter: PdfConverter,
}
#[derive(Debug, Copy, Clone)]
#[rustfmt::skip]
pub enum PageSize {
A1, A2, A3, A4, A5, A6, A7, A8, A9,
B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, B10,
C5E, Comm10E, DLE, Executive, Folio, Ledger, Legal, Letter, Tabloid,
Custom(Size, Size)
}
impl PageSize {
#[rustfmt::skip]
fn value(&self) -> Cow<'static, str> {
use self::PageSize::*;
match *self {
A1 => "A1", A2 => "A2", A3 => "A3", A4 => "A4", A5 => "A5",
A6 => "A6", A7 => "A7", A8 => "A8", A9 => "A9",
B0 => "B0", B1 => "B1", B2 => "B2", B3 => "B3", B4 => "B4", B5 => "B5",
B6 => "B6", B7 => "B7", B8 => "B8", B9 => "B9", B10 => "B10",
C5E => "C5E", Comm10E => "Comm10E", DLE => "DLE", Executive => "Executive", Folio => "Folio",
Ledger => "Ledger", Legal => "Legal", Letter => "Letter", Tabloid => "Tabloid",
Custom(_,_) => "Custom"
}.into()
}
}
#[derive(Debug, Copy, Clone)]
pub enum Size {
Millimeters(u32),
Inches(u32),
}
impl Size {
fn value(&self) -> String {
match self {
Size::Millimeters(ref n) => format!("{}mm", n),
Size::Inches(ref n) => format!("{}in", n),
}
}
}
#[derive(Debug, Copy, Clone)]
pub enum Orientation {
Landscape,
Portrait,
}
#[derive(Debug, Copy, Clone)]
pub struct Margin {
pub top: Size,
pub bottom: Size,
pub left: Size,
pub right: Size,
}
impl From<Size> for Margin {
fn from(size: Size) -> Margin {
Margin {
top: size,
bottom: size,
left: size,
right: size,
}
}
}
impl From<(Size, Size)> for Margin {
fn from(sizes: (Size, Size)) -> Margin {
Margin {
top: sizes.0,
bottom: sizes.0,
left: sizes.1,
right: sizes.1,
}
}
}
impl From<(Size, Size, Size)> for Margin {
fn from(sizes: (Size, Size, Size)) -> Margin {
Margin {
top: sizes.0,
bottom: sizes.2,
left: sizes.1,
right: sizes.1,
}
}
}
impl From<(Size, Size, Size, Size)> for Margin {
fn from(sizes: (Size, Size, Size, Size)) -> Margin {
Margin {
top: sizes.0,
bottom: sizes.2,
left: sizes.3,
right: sizes.1,
}
}
}
pub struct PdfApplication {
_guard: PdfGuard,
}
impl PdfApplication {
pub fn new() -> Result<PdfApplication> {
pdf_init().map(|guard| PdfApplication { _guard: guard })
}
pub fn builder(&self) -> PdfBuilder {
PdfBuilder {
gs: HashMap::new(),
os: HashMap::new(),
}
}
}
#[derive(Clone)]
pub struct PdfBuilder {
gs: HashMap<&'static str, Cow<'static, str>>,
os: HashMap<&'static str, Cow<'static, str>>,
}
impl PdfBuilder {
pub fn page_size(&mut self, page_size: PageSize) -> &mut PdfBuilder {
match page_size {
PageSize::Custom(ref w, ref h) => {
self.gs.insert("size.width", w.value().into());
self.gs.insert("size.height", h.value().into());
}
_ => {
self.gs.insert("size.pageSize", page_size.value());
}
};
self
}
pub fn margin<M: Into<Margin>>(&mut self, margin: M) -> &mut PdfBuilder {
let m = margin.into();
self.gs.insert("margin.top", m.top.value().into());
self.gs.insert("margin.bottom", m.bottom.value().into());
self.gs.insert("margin.left", m.left.value().into());
self.gs.insert("margin.right", m.right.value().into());
self
}
pub fn orientation(&mut self, orientation: Orientation) -> &mut PdfBuilder {
let value = match orientation {
Orientation::Landscape => "Landscape",
Orientation::Portrait => "Portrait",
};
self.gs.insert("orientation", value.into());
self
}
pub fn dpi(&mut self, dpi: u32) -> &mut PdfBuilder {
self.gs.insert("dpi", dpi.to_string().into());
self
}
pub fn image_quality(&mut self, image_quality: u32) -> &mut PdfBuilder {
self.gs
.insert("imageQuality", image_quality.to_string().into());
self
}
pub fn title(&mut self, title: &str) -> &mut PdfBuilder {
self.gs.insert("documentTitle", title.to_string().into());
self
}
pub fn outline(&mut self, outline_depth: Option<u32>) -> &mut PdfBuilder {
match outline_depth {
Some(_depth) => {
self.gs.insert("outline", "true".into());
}
None => {
self.gs.insert("outline", "false".into());
}
}
self
}
pub unsafe fn global_setting<S: Into<Cow<'static, str>>>(
&mut self,
name: &'static str,
value: S,
) -> &mut PdfBuilder {
self.gs.insert(name, value.into());
self
}
pub unsafe fn object_setting<S: Into<Cow<'static, str>>>(
&mut self,
name: &'static str,
value: S,
) -> &mut PdfBuilder {
self.os.insert(name, value.into());
self
}
pub fn build_from_url<'a, 'b>(&'a mut self, url: Url) -> Result<PdfOutput<'b>> {
let global = self.global_settings()?;
let object = self.object_settings()?;
let mut converter = global.create_converter();
converter.add_page_object(object, url.as_str());
converter.convert()
}
pub fn build_from_path<'a, 'b, P: AsRef<Path>>(&'a mut self, path: P) -> Result<PdfOutput<'b>> {
let global = self.global_settings()?;
let object = self.object_settings()?;
let mut converter = global.create_converter();
converter.add_page_object(object, &path.as_ref().to_string_lossy());
converter.convert()
}
pub fn build_from_html<'a, 'b, S: AsRef<str>>(&'a mut self, html: S) -> Result<PdfOutput<'b>> {
let global = self.global_settings()?;
let object = self.object_settings()?;
let mut converter = global.create_converter();
converter.add_html_object(object, html.as_ref());
converter.convert()
}
pub fn global_settings(&self) -> Result<PdfGlobalSettings> {
let mut global = PdfGlobalSettings::new()?;
for (ref name, ref val) in &self.gs {
unsafe { global.set(name, &val) }?;
}
Ok(global)
}
pub fn object_settings(&self) -> Result<PdfObjectSettings> {
let mut object = PdfObjectSettings::new();
for (ref name, ref val) in &self.os {
unsafe { object.set(name, &val) }?;
}
Ok(object)
}
}
impl<'a> PdfOutput<'a> {
pub fn save<P: AsRef<Path>>(&mut self, path: P) -> io::Result<File> {
let mut file = File::create(path)?;
let _ = io::copy(self, &mut file)?;
Ok(file)
}
}
impl<'a> Read for PdfOutput<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.data.read(buf)
}
}
impl<'a> std::fmt::Debug for PdfOutput<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.data.fmt(f)
}
}