1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//! Wapper type for shared metadata between XMP Metadata and the `DocumentInfo` dictionary

extern crate lopdf;
extern crate chrono;

use {
	IccProfileType, PdfConformance, XmpMetadata, DocumentInfo, IccProfile
};

use glob_defines::ICC_PROFILE_ECI_V2;

/// This is a wrapper in order to keep shared data between the documents XMP metadata and
/// the "Info" dictionary in sync
#[derive(Debug, Clone)]
pub struct PdfMetadata {
	/// Creation date of the document
	pub creation_date: chrono::DateTime<chrono::Local>,
	/// Modification date of the document
	pub modification_date: chrono::DateTime<chrono::Local>,
	/// Creation date of the metadata
	pub metadata_date: chrono::DateTime<chrono::Local>,
	/// PDF document title
	pub document_title: String,
	/// Is the document trapped?
	pub trapping: bool,
	/// PDF document version
	pub document_version: u32,
	/// PDF Standard
	pub conformance: PdfConformance,
	/// XMP Metadata. Is ignored on save if the PDF conformance does not allow XMP
	pub xmp_metadata: XmpMetadata,
	/// PDF Info dictionary. Contains metadata for this document
	pub document_info: DocumentInfo,
	/// Target color profile
	pub target_icc_profile: Option<IccProfile>,
}

impl PdfMetadata {

	/// Creates a new metadat object
	pub fn new<S>(title: S, document_version: u32, trapping: bool, conformance: PdfConformance)
	-> Self where S: Into<String>
	{
		let current_time = chrono::Local::now();

		Self {
			creation_date: current_time,
			modification_date: current_time,
			metadata_date: current_time,
			document_title: title.into(),
			trapping: trapping,
			document_version: document_version,
			conformance: conformance,
			xmp_metadata: XmpMetadata::new(Some("default".into()), 1),
			document_info: DocumentInfo::new(),
			target_icc_profile: None,
		}
	}

	/// Consumes the metadata, returning the (Option<xmp_metadata>, document_info, icc_profile_stream).
	pub fn into_obj(self)
	-> (Option<lopdf::Object>, lopdf::Object, Option<IccProfile>)
	{
		let xmp_obj = {
			if self.conformance.must_have_xmp_metadata() {
				Some(self.xmp_metadata.into_obj(
					 	self.conformance.clone(),
						self.trapping,
						self.creation_date,
						self.modification_date,
						self.metadata_date,
						self.document_title.clone()))
			} else { 
				None
			}
		}; 

		let doc_info_obj = self.document_info.into_obj(self.document_title,
													   self.trapping,
													   self.conformance.clone(),
													   self.creation_date,
													   self.modification_date);
		// add icc profile if necessary
		let icc_profile = {
		    if self.conformance.must_have_icc_profile() {
		        match self.target_icc_profile {
		            Some(icc) => Some(icc),
		            None =>      Some(IccProfile::new(ICC_PROFILE_ECI_V2.to_vec(), IccProfileType::Cmyk)
		            			      .with_alternate_profile(false)
		            			      .with_range(true)),
		        }
		    } else {
		        None
		    }
		};

		(xmp_obj, doc_info_obj, icc_profile)
	}
}