use std::io;
use object::*;
use err::*;
use content::Content;
#[derive(Debug)]
pub enum PagesNode {
Tree (PageTree),
Leaf (Page),
}
impl Object for PagesNode {
fn serialize<W: io::Write>(&self, out: &mut W) -> io::Result<()> {
match *self {
PagesNode::Tree (ref t) => t.serialize(out),
PagesNode::Leaf (ref l) => l.serialize(out),
}
}
fn from_primitive(p: Primitive, r: &Resolve) -> Result<PagesNode> {
let dict = Dictionary::from_primitive(p, r)?;
Ok(
match dict["Type"].clone().to_name()?.as_str() {
"Page" => PagesNode::Leaf (Page::from_primitive(Primitive::Dictionary(dict), r)?),
"Pages" => PagesNode::Tree (PageTree::from_primitive(Primitive::Dictionary(dict), r)?),
other => bail!(ErrorKind::WrongDictionaryType {expected: "Page or Pages".into(), found: other.into()}),
}
)
}
}
#[derive(Object, Default)]
pub struct Catalog {
#[pdf(key="Pages")]
pub pages: PageTree,
#[pdf(key="Names")]
pub names: Option<NameDictionary>,
#[pdf(key="StructTreeRoot")]
pub struct_tree_root: Option<StructTreeRoot>,
}
#[derive(Object, Debug, Default)]
#[pdf(Type = "Pages")]
pub struct PageTree {
#[pdf(key="Parent")]
pub parent: Option<Ref<PageTree>>,
#[pdf(key="Kids")]
pub kids: Vec<PagesNode>,
#[pdf(key="Count")]
pub count: i32,
#[pdf(key="Resources")]
pub resources: Option<Resources>,
}
#[derive(Object, Debug)]
pub struct Page {
#[pdf(key="Parent")]
pub parent: Ref<PageTree>,
#[pdf(key="Resources")]
pub resources: Option<Resources>,
#[pdf(key="MediaBox")]
pub media_box: Option<Rect>,
#[pdf(key="CropBox")]
pub crop_box: Option<Rect>,
#[pdf(key="TrimBox")]
pub trim_box: Option<Rect>,
#[pdf(key="Contents")]
pub contents: Vec<Content>
}
impl Page {
pub fn new(parent: Ref<PageTree>) -> Page {
Page {
parent: parent,
media_box: None,
crop_box: None,
trim_box: None,
resources: None,
contents: Vec::new(),
}
}
}
#[derive(Object)]
pub struct PageLabel {
#[pdf(key="S")]
style: Option<Counter>,
#[pdf(key="P")]
prefix: Option<PdfString>,
#[pdf(key="St")]
start: Option<usize>
}
#[derive(Object, Debug)]
pub struct Resources {
#[pdf(key="ExtGState")]
pub ext_g_state: Option<GraphicsStateParameters>,
#[pdf(key="XObject")]
pub xobjects: Option<BTreeMap<String, XObject>>,
#[pdf(key="Font")]
pub fonts: Option<BTreeMap<String, Font>>,
}
#[derive(Debug)]
pub enum Font {
Type0,
Type1,
MMType1,
Type3,
TrueType,
CIDFontType0,
CIDFontType2,
}
impl Object for Font {
fn serialize<W: io::Write>(&self, _out: &mut W) -> io::Result<()> { unimplemented!() }
fn from_primitive(p: Primitive, resolve: &Resolve) -> Result<Self> {
let dict = Dictionary::from_primitive(p, resolve)?;
let ty = dict.get("Type")
.ok_or(Error::from(ErrorKind::EntryNotFound { key: "Type" }))?.clone()
.to_name()?;
if ty != "Font" {
bail!("Font dictionary: /Type != Font");
}
match dict.get("Subtype") {
Some(&Primitive::Name(ref name)) =>
Ok(match name.as_str() {
"Type0" => Font::Type0,
"Type1" => Font::Type1,
"MMType1" => Font::MMType1,
"Type3" => Font::Type3,
"TrueType" => Font::TrueType,
"CIDFontType0" => Font::CIDFontType0,
"CIDFontType2" => Font::CIDFontType2,
s => bail!("Wrong /Type {} for font dictionary.", s),
}),
_ => bail!(ErrorKind::EntryNotFound {key: "Type"}),
}
}
}
#[derive(Object, Debug)]
#[pdf(Type = "ExtGState?")]
pub struct GraphicsStateParameters {
}
#[derive(Debug)]
pub enum XObject {
Postscript (PostScriptXObject),
Image (ImageXObject),
Form (FormXObject),
}
impl Object for XObject {
fn serialize<W: io::Write>(&self, _out: &mut W) -> io::Result<()> {
unimplemented!();
}
fn from_primitive(p: Primitive, resolve: &Resolve) -> Result<Self> {
let stream = PdfStream::from_primitive(p, resolve)?;
let ty = stream.info.get("Type")
.ok_or(Error::from(ErrorKind::EntryNotFound { key: "Type" }))?.clone()
.to_name()?;
if ty != "XObject" {
bail!("XObject: /Type != XObject");
}
let subty = stream.info.get("Subtype")
.ok_or(Error::from(ErrorKind::EntryNotFound { key: "Subtype"}))?.clone()
.to_name()?;
Ok(match subty.as_str() {
"PS" => XObject::Postscript (PostScriptXObject::from_primitive(Primitive::Stream(stream), resolve)?),
"Image" => XObject::Image (ImageXObject::from_primitive(Primitive::Stream(stream), resolve)?),
"Form" => XObject::Form (FormXObject::from_primitive(Primitive::Stream(stream), resolve)?),
s => bail!("XObject: invalid /Subtype {}", s),
})
}
}
pub type PostScriptXObject = Stream<PostScriptDict>;
pub type ImageXObject = Stream<ImageDict>;
pub type FormXObject = Stream<FormDict>;
#[derive(Object, Debug)]
#[pdf(Type="XObject", Subtype="PS")]
pub struct PostScriptDict {
}
#[derive(Object, Debug, Clone)]
#[pdf(Type="XObject", Subtype="Image")]
pub struct ImageDict {
#[pdf(key="Width")]
pub width: i32,
#[pdf(key="Height")]
pub height: i32,
#[pdf(key="BitsPerComponent")]
pub bits_per_component: i32,
#[pdf(key="Intent")]
pub intent: Option<RenderingIntent>,
#[pdf(key="ImageMask", default="false")]
pub image_mask: bool,
#[pdf(key="Decode")]
pub decode: Vec<i32>,
#[pdf(key="Interpolate", default="false")]
pub interpolate: bool,
#[pdf(key="StructParent")]
pub struct_parent: Option<i32>,
#[pdf(key="ID")]
pub id: Option<PdfString>,
}
#[derive(Object, Debug, Clone)]
pub enum RenderingIntent {
AbsoluteColorimetric,
RelativeColorimetric,
Saturation,
Perceptual,
}
#[derive(Object, Debug)]
#[pdf(Type="XObject", Subtype="Form")]
pub struct FormDict {
}
pub enum Counter {
Arabic,
RomanUpper,
RomanLower,
AlphaUpper,
AlphaLower
}
impl Object for Counter {
fn serialize<W: io::Write>(&self, out: &mut W) -> io::Result<()> {
let style_code = match *self {
Counter::Arabic => "D",
Counter::RomanLower => "r",
Counter::RomanUpper => "R",
Counter::AlphaLower => "a",
Counter::AlphaUpper => "A"
};
out.write_all(style_code.as_bytes())?;
Ok(())
}
fn from_primitive(_: Primitive, _: &Resolve) -> Result<Self> {
unimplemented!();
}
}
pub enum NameTreeNode<T> {
Intermediate (Vec<Ref<NameTree<T>>>),
Leaf (Vec<(PdfString, T)>)
}
pub struct NameTree<T> {
limits: Option<(PdfString, PdfString)>,
node: NameTreeNode<T>,
}
impl<T: Object> Object for NameTree<T> {
fn serialize<W: io::Write>(&self, _out: &mut W) -> io::Result<()> {
unimplemented!();
}
fn from_primitive(p: Primitive, resolve: &Resolve) -> Result<Self> {
let mut dict = p.to_dictionary(resolve).chain_err(|| "NameTree<T>")?;
let limits = match dict.remove("Limits") {
Some(limits) => {
let limits = limits.to_array(resolve)?;
if limits.len() != 2 {
bail!("Error reading NameTree: 'Limits' is not of length 2");
}
let min = limits[0].clone().to_string()?;
let max = limits[1].clone().to_string()?;
Some((min, max))
}
None => None
};
let kids = dict.remove("Kids");
let names = dict.remove("Names");
Ok(match kids {
Some(kids) => {
let kids = kids.to_array(resolve)?.iter().map(|kid|
Ref::<NameTree<T>>::from_primitive(kid.clone(), resolve)
).collect::<Result<Vec<_>>>()?;
NameTree {
limits: limits,
node: NameTreeNode::Intermediate (kids)
}
}
None =>
match names {
Some(names) => {
let names = names.to_array(resolve)?;
let mut new_names = Vec::new();
for pair in names.chunks(2) {
let name = pair[0].clone().to_string()?;
let value = T::from_primitive(pair[1].clone(), resolve)?;
new_names.push((name, value));
}
NameTree {
limits: limits,
node: NameTreeNode::Leaf (new_names),
}
}
None => bail!("Neither Kids nor Names present in NameTree node.")
}
})
}
}
#[derive(Object)]
pub struct NameDictionary {
#[pdf(key="EmbeddedFiles")]
embedded_files: Option<NameTree<FileSpec>>,
}
#[derive(Object, Debug, Clone)]
pub struct FileSpec {
#[pdf(key="EF")]
ef: Option<Files<EmbeddedFile>>,
}
#[derive(Object, Debug, Clone)]
pub struct Files<T: Object> {
#[pdf(key="F")]
f: Option<T>,
#[pdf(key="UF")]
uf: Option<T>,
#[pdf(key="DOS")]
dos: Option<T>,
#[pdf(key="Mac")]
mac: Option<T>,
#[pdf(key="Unix")]
unix: Option<T>,
}
#[derive(Object, Debug, Clone)]
pub struct EmbeddedFile {
#[pdf(key="Params")]
params: Option<EmbeddedFileParamDict>,
}
#[derive(Object, Debug, Clone)]
pub struct EmbeddedFileParamDict {
#[pdf(key="Size")]
size: Option<i32>,
}
pub fn write_list<'a, W, T: 'a, I>(out: &mut W, mut iter: I) -> io::Result<()>
where W: io::Write, T: Object, I: Iterator<Item=&'a T>
{
write!(out, "[")?;
if let Some(first) = iter.next() {
first.serialize(out)?;
for other in iter {
out.write_all(b", ")?;
other.serialize(out)?;
}
}
write!(out, "]")
}
#[derive(Object)]
pub struct Outlines {
#[pdf(key="Count")]
pub count: usize
}
#[derive(Debug)]
pub struct Rect {
pub left: f32,
pub right: f32,
pub top: f32,
pub bottom: f32
}
impl Object for Rect {
fn serialize<W: io::Write>(&self, out: &mut W) -> io::Result<()> {
write!(out, "[{} {} {} {}]", self.left, self.top, self.right, self.bottom)
}
fn from_primitive(p: Primitive, r: &Resolve) -> Result<Self> {
let arr = p.to_array(r)?;
if arr.len() != 4 {
bail!("len != 4");
}
Ok(Rect {
left: arr[0].as_number()?,
right: arr[1].as_number()?,
top: arr[2].as_number()?,
bottom: arr[3].as_number()?
})
}
}
#[derive(Object)]
pub struct MarkInformation {
#[pdf(key="Marked", default="false")]
pub marked: bool,
#[pdf(key="UserProperties", default="false")]
pub user_properties: bool,
#[pdf(key="Suspects", default="false")]
pub suspects: bool,
}
#[derive(Object)]
#[pdf(Type = "StructTreeRoot")]
pub struct StructTreeRoot {
#[pdf(key="K")]
pub children: Vec<StructElem>,
}
#[derive(Object)]
pub struct StructElem {
#[pdf(key="S")]
struct_type: StructType,
#[pdf(key="P")]
parent: Ref<StructElem>,
#[pdf(key="ID")]
id: Option<PdfString>,
#[pdf(key="Pg")]
page: Option<Ref<Page>>,
}
#[derive(Object)]
pub enum StructType {
Document,
Part,
Art,
Sect,
Div,
BlockQuote,
Caption,
TOC,
TOCI,
Index,
NonStruct,
Private,
Book,
}