1use crate::document::Document;
2use crate::error::Result;
3use crate::objects::{Dictionary, Object, ObjectId};
4use crate::text::fonts::embedding::CjkFontType;
5use crate::writer::{ObjectStreamConfig, ObjectStreamWriter, XRefStreamWriter};
6use chrono::{DateTime, Utc};
7use std::collections::HashMap;
8use std::io::{BufWriter, Write};
9use std::path::Path;
10
11#[derive(Debug, Clone)]
13pub struct WriterConfig {
14 pub use_xref_streams: bool,
16 pub use_object_streams: bool,
18 pub pdf_version: String,
20 pub compress_streams: bool,
22}
23
24impl Default for WriterConfig {
25 fn default() -> Self {
26 Self {
27 use_xref_streams: false,
28 use_object_streams: false,
29 pdf_version: "1.7".to_string(),
30 compress_streams: true,
31 }
32 }
33}
34
35impl WriterConfig {
36 pub fn modern() -> Self {
38 Self {
39 use_xref_streams: true,
40 use_object_streams: true,
41 pdf_version: "1.5".to_string(),
42 compress_streams: true,
43 }
44 }
45
46 pub fn legacy() -> Self {
48 Self {
49 use_xref_streams: false,
50 use_object_streams: false,
51 pdf_version: "1.4".to_string(),
52 compress_streams: true,
53 }
54 }
55}
56
57pub struct PdfWriter<W: Write> {
58 writer: W,
59 xref_positions: HashMap<ObjectId, u64>,
60 current_position: u64,
61 next_object_id: u32,
62 catalog_id: Option<ObjectId>,
64 pages_id: Option<ObjectId>,
65 info_id: Option<ObjectId>,
66 #[allow(dead_code)]
68 field_widget_map: HashMap<String, Vec<ObjectId>>, #[allow(dead_code)]
70 field_id_map: HashMap<String, ObjectId>, form_field_ids: Vec<ObjectId>, page_ids: Vec<ObjectId>, config: WriterConfig,
75 document_used_chars: Option<std::collections::HashSet<char>>,
77 buffered_objects: HashMap<ObjectId, Vec<u8>>,
79 compressed_object_map: HashMap<ObjectId, (ObjectId, u32)>, }
81
82impl<W: Write> PdfWriter<W> {
83 pub fn new_with_writer(writer: W) -> Self {
84 Self::with_config(writer, WriterConfig::default())
85 }
86
87 pub fn with_config(writer: W, config: WriterConfig) -> Self {
88 Self {
89 writer,
90 xref_positions: HashMap::new(),
91 current_position: 0,
92 next_object_id: 1, catalog_id: None,
94 pages_id: None,
95 info_id: None,
96 field_widget_map: HashMap::new(),
97 field_id_map: HashMap::new(),
98 form_field_ids: Vec::new(),
99 page_ids: Vec::new(),
100 config,
101 document_used_chars: None,
102 buffered_objects: HashMap::new(),
103 compressed_object_map: HashMap::new(),
104 }
105 }
106
107 pub fn write_document(&mut self, document: &mut Document) -> Result<()> {
108 if !document.used_characters.is_empty() {
110 self.document_used_chars = Some(document.used_characters.clone());
111 }
112
113 self.write_header()?;
114
115 self.catalog_id = Some(self.allocate_object_id());
117 self.pages_id = Some(self.allocate_object_id());
118 self.info_id = Some(self.allocate_object_id());
119
120 let font_refs = self.write_fonts(document)?;
122
123 self.write_pages(document, &font_refs)?;
125
126 self.write_form_fields(document)?;
128
129 self.write_catalog(document)?;
131
132 self.write_info(document)?;
134
135 if self.config.use_object_streams {
137 self.flush_object_streams()?;
138 }
139
140 let xref_position = self.current_position;
142 if self.config.use_xref_streams {
143 self.write_xref_stream()?;
144 } else {
145 self.write_xref()?;
146 }
147
148 if !self.config.use_xref_streams {
150 self.write_trailer(xref_position)?;
151 }
152
153 if let Ok(()) = self.writer.flush() {
154 }
156 Ok(())
157 }
158
159 fn write_header(&mut self) -> Result<()> {
160 let header = format!("%PDF-{}\n", self.config.pdf_version);
161 self.write_bytes(header.as_bytes())?;
162 self.write_bytes(&[b'%', 0xE2, 0xE3, 0xCF, 0xD3, b'\n'])?;
164 Ok(())
165 }
166
167 fn write_catalog(&mut self, document: &mut Document) -> Result<()> {
168 let catalog_id = self.catalog_id.expect("catalog_id must be set");
169 let pages_id = self.pages_id.expect("pages_id must be set");
170
171 let mut catalog = Dictionary::new();
172 catalog.set("Type", Object::Name("Catalog".to_string()));
173 catalog.set("Pages", Object::Reference(pages_id));
174
175 if let Some(_form_manager) = &document.form_manager {
178 if document.acro_form.is_none() {
180 document.acro_form = Some(crate::forms::AcroForm::new());
181 }
182 }
183
184 if let Some(acro_form) = &document.acro_form {
186 let acro_form_id = self.allocate_object_id();
188
189 self.write_object(acro_form_id, Object::Dictionary(acro_form.to_dict()))?;
191
192 catalog.set("AcroForm", Object::Reference(acro_form_id));
194 }
195
196 if let Some(outline_tree) = &document.outline {
198 if !outline_tree.items.is_empty() {
199 let outline_root_id = self.write_outline_tree(outline_tree)?;
200 catalog.set("Outlines", Object::Reference(outline_root_id));
201 }
202 }
203
204 if let Some(struct_tree) = &document.struct_tree {
206 if !struct_tree.is_empty() {
207 let struct_tree_root_id = self.write_struct_tree(struct_tree)?;
208 catalog.set("StructTreeRoot", Object::Reference(struct_tree_root_id));
209 catalog.set("MarkInfo", {
211 let mut mark_info = Dictionary::new();
212 mark_info.set("Marked", Object::Boolean(true));
213 Object::Dictionary(mark_info)
214 });
215 }
216 }
217
218 let xmp_metadata = document.create_xmp_metadata();
221 let xmp_packet = xmp_metadata.to_xmp_packet();
222 let metadata_id = self.allocate_object_id();
223
224 let mut metadata_dict = Dictionary::new();
226 metadata_dict.set("Type", Object::Name("Metadata".to_string()));
227 metadata_dict.set("Subtype", Object::Name("XML".to_string()));
228 metadata_dict.set("Length", Object::Integer(xmp_packet.len() as i64));
229
230 self.write_object(
232 metadata_id,
233 Object::Stream(metadata_dict, xmp_packet.into_bytes()),
234 )?;
235
236 catalog.set("Metadata", Object::Reference(metadata_id));
238
239 self.write_object(catalog_id, Object::Dictionary(catalog))?;
240 Ok(())
241 }
242
243 fn write_page_content(&mut self, content_id: ObjectId, page: &crate::page::Page) -> Result<()> {
244 let mut page_copy = page.clone();
245 let content = page_copy.generate_content()?;
246
247 #[cfg(feature = "compression")]
249 {
250 use crate::objects::Stream;
251 let mut stream = Stream::new(content);
252 if self.config.compress_streams {
254 stream.compress_flate()?;
255 }
256
257 self.write_object(
258 content_id,
259 Object::Stream(stream.dictionary().clone(), stream.data().to_vec()),
260 )?;
261 }
262
263 #[cfg(not(feature = "compression"))]
264 {
265 let mut stream_dict = Dictionary::new();
266 stream_dict.set("Length", Object::Integer(content.len() as i64));
267
268 self.write_object(content_id, Object::Stream(stream_dict, content))?;
269 }
270
271 Ok(())
272 }
273
274 fn write_outline_tree(
275 &mut self,
276 outline_tree: &crate::structure::OutlineTree,
277 ) -> Result<ObjectId> {
278 let outline_root_id = self.allocate_object_id();
280
281 let mut outline_root = Dictionary::new();
282 outline_root.set("Type", Object::Name("Outlines".to_string()));
283
284 if !outline_tree.items.is_empty() {
285 let mut item_ids = Vec::new();
287
288 fn count_items(items: &[crate::structure::OutlineItem]) -> usize {
290 let mut count = items.len();
291 for item in items {
292 count += count_items(&item.children);
293 }
294 count
295 }
296
297 let total_items = count_items(&outline_tree.items);
298
299 for _ in 0..total_items {
301 item_ids.push(self.allocate_object_id());
302 }
303
304 let mut id_index = 0;
305
306 let first_id = item_ids[0];
308 let last_id = item_ids[outline_tree.items.len() - 1];
309
310 outline_root.set("First", Object::Reference(first_id));
311 outline_root.set("Last", Object::Reference(last_id));
312
313 let visible_count = outline_tree.visible_count();
315 outline_root.set("Count", Object::Integer(visible_count));
316
317 let mut written_items = Vec::new();
319
320 for (i, item) in outline_tree.items.iter().enumerate() {
321 let item_id = item_ids[id_index];
322 id_index += 1;
323
324 let prev_id = if i > 0 { Some(item_ids[i - 1]) } else { None };
325 let next_id = if i < outline_tree.items.len() - 1 {
326 Some(item_ids[i + 1])
327 } else {
328 None
329 };
330
331 let children_ids = self.write_outline_item(
333 item,
334 item_id,
335 outline_root_id,
336 prev_id,
337 next_id,
338 &mut item_ids,
339 &mut id_index,
340 )?;
341
342 written_items.extend(children_ids);
343 }
344 }
345
346 self.write_object(outline_root_id, Object::Dictionary(outline_root))?;
347 Ok(outline_root_id)
348 }
349
350 #[allow(clippy::too_many_arguments)]
351 fn write_outline_item(
352 &mut self,
353 item: &crate::structure::OutlineItem,
354 item_id: ObjectId,
355 parent_id: ObjectId,
356 prev_id: Option<ObjectId>,
357 next_id: Option<ObjectId>,
358 all_ids: &mut Vec<ObjectId>,
359 id_index: &mut usize,
360 ) -> Result<Vec<ObjectId>> {
361 let mut written_ids = vec![item_id];
362
363 let (first_child_id, last_child_id) = if !item.children.is_empty() {
365 let first_idx = *id_index;
366 let first_id = all_ids[first_idx];
367 let last_idx = first_idx + item.children.len() - 1;
368 let last_id = all_ids[last_idx];
369
370 for (i, child) in item.children.iter().enumerate() {
372 let child_id = all_ids[*id_index];
373 *id_index += 1;
374
375 let child_prev = if i > 0 {
376 Some(all_ids[first_idx + i - 1])
377 } else {
378 None
379 };
380 let child_next = if i < item.children.len() - 1 {
381 Some(all_ids[first_idx + i + 1])
382 } else {
383 None
384 };
385
386 let child_ids = self.write_outline_item(
387 child, child_id, item_id, child_prev, child_next, all_ids, id_index,
389 )?;
390
391 written_ids.extend(child_ids);
392 }
393
394 (Some(first_id), Some(last_id))
395 } else {
396 (None, None)
397 };
398
399 let item_dict = crate::structure::outline_item_to_dict(
401 item,
402 parent_id,
403 first_child_id,
404 last_child_id,
405 prev_id,
406 next_id,
407 );
408
409 self.write_object(item_id, Object::Dictionary(item_dict))?;
410
411 Ok(written_ids)
412 }
413
414 fn write_struct_tree(
416 &mut self,
417 struct_tree: &crate::structure::StructTree,
418 ) -> Result<ObjectId> {
419 let struct_tree_root_id = self.allocate_object_id();
421 let mut element_ids = Vec::new();
422 for _ in 0..struct_tree.len() {
423 element_ids.push(self.allocate_object_id());
424 }
425
426 let mut parent_map: std::collections::HashMap<usize, ObjectId> =
428 std::collections::HashMap::new();
429
430 if let Some(root_index) = struct_tree.root_index() {
432 parent_map.insert(root_index, struct_tree_root_id);
433
434 fn map_children_parents(
436 tree: &crate::structure::StructTree,
437 parent_index: usize,
438 parent_id: ObjectId,
439 element_ids: &[ObjectId],
440 parent_map: &mut std::collections::HashMap<usize, ObjectId>,
441 ) {
442 if let Some(parent_elem) = tree.get(parent_index) {
443 for &child_index in &parent_elem.children {
444 parent_map.insert(child_index, parent_id);
445 map_children_parents(
446 tree,
447 child_index,
448 element_ids[child_index],
449 element_ids,
450 parent_map,
451 );
452 }
453 }
454 }
455
456 map_children_parents(
457 struct_tree,
458 root_index,
459 element_ids[root_index],
460 &element_ids,
461 &mut parent_map,
462 );
463 }
464
465 for (index, element) in struct_tree.iter().enumerate() {
467 let element_id = element_ids[index];
468 let mut element_dict = Dictionary::new();
469
470 element_dict.set("Type", Object::Name("StructElem".to_string()));
471 element_dict.set("S", Object::Name(element.structure_type.as_pdf_name()));
472
473 if let Some(&parent_id) = parent_map.get(&index) {
475 element_dict.set("P", Object::Reference(parent_id));
476 }
477
478 if let Some(ref id) = element.id {
480 element_dict.set("ID", Object::String(id.clone()));
481 }
482
483 if let Some(ref lang) = element.attributes.lang {
485 element_dict.set("Lang", Object::String(lang.clone()));
486 }
487 if let Some(ref alt) = element.attributes.alt {
488 element_dict.set("Alt", Object::String(alt.clone()));
489 }
490 if let Some(ref actual_text) = element.attributes.actual_text {
491 element_dict.set("ActualText", Object::String(actual_text.clone()));
492 }
493 if let Some(ref title) = element.attributes.title {
494 element_dict.set("T", Object::String(title.clone()));
495 }
496 if let Some(bbox) = element.attributes.bbox {
497 element_dict.set(
498 "BBox",
499 Object::Array(vec![
500 Object::Real(bbox[0]),
501 Object::Real(bbox[1]),
502 Object::Real(bbox[2]),
503 Object::Real(bbox[3]),
504 ]),
505 );
506 }
507
508 let mut kids = Vec::new();
510
511 for &child_index in &element.children {
513 kids.push(Object::Reference(element_ids[child_index]));
514 }
515
516 for mcid_ref in &element.mcids {
518 let mut mcr = Dictionary::new();
519 mcr.set("Type", Object::Name("MCR".to_string()));
520 mcr.set("Pg", Object::Integer(mcid_ref.page_index as i64));
521 mcr.set("MCID", Object::Integer(mcid_ref.mcid as i64));
522 kids.push(Object::Dictionary(mcr));
523 }
524
525 if !kids.is_empty() {
526 element_dict.set("K", Object::Array(kids));
527 }
528
529 self.write_object(element_id, Object::Dictionary(element_dict))?;
530 }
531
532 let mut struct_tree_root = Dictionary::new();
534 struct_tree_root.set("Type", Object::Name("StructTreeRoot".to_string()));
535
536 if let Some(root_index) = struct_tree.root_index() {
538 struct_tree_root.set("K", Object::Reference(element_ids[root_index]));
539 }
540
541 if !struct_tree.role_map.mappings().is_empty() {
543 let mut role_map = Dictionary::new();
544 for (custom_type, standard_type) in struct_tree.role_map.mappings() {
545 role_map.set(
546 custom_type.as_str(),
547 Object::Name(standard_type.as_pdf_name().to_string()),
548 );
549 }
550 struct_tree_root.set("RoleMap", Object::Dictionary(role_map));
551 }
552
553 self.write_object(struct_tree_root_id, Object::Dictionary(struct_tree_root))?;
554 Ok(struct_tree_root_id)
555 }
556
557 fn write_form_fields(&mut self, document: &mut Document) -> Result<()> {
558 if !self.form_field_ids.is_empty() {
560 if let Some(acro_form) = &mut document.acro_form {
561 acro_form.fields.clear();
563 for field_id in &self.form_field_ids {
564 acro_form.add_field(*field_id);
565 }
566
567 acro_form.need_appearances = true;
569 if acro_form.da.is_none() {
570 acro_form.da = Some("/Helv 12 Tf 0 g".to_string());
571 }
572 }
573 }
574 Ok(())
575 }
576
577 fn write_info(&mut self, document: &Document) -> Result<()> {
578 let info_id = self.info_id.expect("info_id must be set");
579 let mut info_dict = Dictionary::new();
580
581 if let Some(ref title) = document.metadata.title {
582 info_dict.set("Title", Object::String(title.clone()));
583 }
584 if let Some(ref author) = document.metadata.author {
585 info_dict.set("Author", Object::String(author.clone()));
586 }
587 if let Some(ref subject) = document.metadata.subject {
588 info_dict.set("Subject", Object::String(subject.clone()));
589 }
590 if let Some(ref keywords) = document.metadata.keywords {
591 info_dict.set("Keywords", Object::String(keywords.clone()));
592 }
593 if let Some(ref creator) = document.metadata.creator {
594 info_dict.set("Creator", Object::String(creator.clone()));
595 }
596 if let Some(ref producer) = document.metadata.producer {
597 info_dict.set("Producer", Object::String(producer.clone()));
598 }
599
600 if let Some(creation_date) = document.metadata.creation_date {
602 let date_string = format_pdf_date(creation_date);
603 info_dict.set("CreationDate", Object::String(date_string));
604 }
605
606 if let Some(mod_date) = document.metadata.modification_date {
608 let date_string = format_pdf_date(mod_date);
609 info_dict.set("ModDate", Object::String(date_string));
610 }
611
612 let edition = if cfg!(feature = "pro") {
615 super::Edition::Pro
616 } else if cfg!(feature = "enterprise") {
617 super::Edition::Enterprise
618 } else {
619 super::Edition::Community
620 };
621
622 let signature = super::PdfSignature::new(document, edition);
623 signature.write_to_info_dict(&mut info_dict);
624
625 self.write_object(info_id, Object::Dictionary(info_dict))?;
626 Ok(())
627 }
628
629 fn write_fonts(&mut self, document: &Document) -> Result<HashMap<String, ObjectId>> {
630 let mut font_refs = HashMap::new();
631
632 for font_name in document.custom_font_names() {
634 if let Some(font) = document.get_custom_font(&font_name) {
635 let font_id = self.write_font_with_unicode_support(&font_name, &font)?;
638 font_refs.insert(font_name.clone(), font_id);
639 }
640 }
641
642 Ok(font_refs)
643 }
644
645 fn write_font_with_unicode_support(
647 &mut self,
648 font_name: &str,
649 font: &crate::fonts::Font,
650 ) -> Result<ObjectId> {
651 self.write_type0_font_from_font(font_name, font)
654 }
655
656 fn write_type0_font_from_font(
658 &mut self,
659 font_name: &str,
660 font: &crate::fonts::Font,
661 ) -> Result<ObjectId> {
662 let used_chars = self.document_used_chars.clone().unwrap_or_else(|| {
664 let mut chars = std::collections::HashSet::new();
666 for ch in "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,!?".chars()
667 {
668 chars.insert(ch);
669 }
670 chars
671 });
672 let font_id = self.allocate_object_id();
674 let descendant_font_id = self.allocate_object_id();
675 let descriptor_id = self.allocate_object_id();
676 let font_file_id = self.allocate_object_id();
677 let to_unicode_id = self.allocate_object_id();
678
679 let (font_data_to_embed, subset_glyph_mapping, original_font_for_widths) =
683 if font.data.len() > 100_000 && !used_chars.is_empty() {
684 match crate::text::fonts::truetype_subsetter::subset_font(
686 font.data.clone(),
687 &used_chars,
688 ) {
689 Ok(subset_result) => {
690 (
693 subset_result.font_data,
694 Some(subset_result.glyph_mapping),
695 font.clone(),
696 )
697 }
698 Err(_) => {
699 if font.data.len() < 25_000_000 {
701 (font.data.clone(), None, font.clone())
702 } else {
703 (Vec::new(), None, font.clone())
705 }
706 }
707 }
708 } else {
709 (font.data.clone(), None, font.clone())
711 };
712
713 if !font_data_to_embed.is_empty() {
714 let mut font_file_dict = Dictionary::new();
715 match font.format {
717 crate::fonts::FontFormat::OpenType => {
718 font_file_dict.set("Subtype", Object::Name("OpenType".to_string()));
720 font_file_dict.set("Length1", Object::Integer(font_data_to_embed.len() as i64));
721 }
722 crate::fonts::FontFormat::TrueType => {
723 font_file_dict.set("Length1", Object::Integer(font_data_to_embed.len() as i64));
725 }
726 }
727 let font_stream_obj = Object::Stream(font_file_dict, font_data_to_embed);
728 self.write_object(font_file_id, font_stream_obj)?;
729 } else {
730 let font_file_dict = Dictionary::new();
732 let font_stream_obj = Object::Stream(font_file_dict, Vec::new());
733 self.write_object(font_file_id, font_stream_obj)?;
734 }
735
736 let mut descriptor = Dictionary::new();
738 descriptor.set("Type", Object::Name("FontDescriptor".to_string()));
739 descriptor.set("FontName", Object::Name(font_name.to_string()));
740 descriptor.set("Flags", Object::Integer(4)); descriptor.set(
742 "FontBBox",
743 Object::Array(vec![
744 Object::Integer(font.descriptor.font_bbox[0] as i64),
745 Object::Integer(font.descriptor.font_bbox[1] as i64),
746 Object::Integer(font.descriptor.font_bbox[2] as i64),
747 Object::Integer(font.descriptor.font_bbox[3] as i64),
748 ]),
749 );
750 descriptor.set(
751 "ItalicAngle",
752 Object::Real(font.descriptor.italic_angle as f64),
753 );
754 descriptor.set("Ascent", Object::Real(font.descriptor.ascent as f64));
755 descriptor.set("Descent", Object::Real(font.descriptor.descent as f64));
756 descriptor.set("CapHeight", Object::Real(font.descriptor.cap_height as f64));
757 descriptor.set("StemV", Object::Real(font.descriptor.stem_v as f64));
758 let font_file_key = match font.format {
760 crate::fonts::FontFormat::OpenType => "FontFile3", crate::fonts::FontFormat::TrueType => "FontFile2", };
763 descriptor.set(font_file_key, Object::Reference(font_file_id));
764 self.write_object(descriptor_id, Object::Dictionary(descriptor))?;
765
766 let mut cid_font = Dictionary::new();
768 cid_font.set("Type", Object::Name("Font".to_string()));
769 let cid_font_subtype =
771 if CjkFontType::should_use_cidfonttype2_for_preview_compatibility(font_name) {
772 "CIDFontType2" } else {
774 match font.format {
775 crate::fonts::FontFormat::OpenType => "CIDFontType0", crate::fonts::FontFormat::TrueType => "CIDFontType2", }
778 };
779 cid_font.set("Subtype", Object::Name(cid_font_subtype.to_string()));
780 cid_font.set("BaseFont", Object::Name(font_name.to_string()));
781
782 let mut cid_system_info = Dictionary::new();
784 let (registry, ordering, supplement) =
785 if let Some(cjk_type) = CjkFontType::detect_from_name(font_name) {
786 cjk_type.cid_system_info()
787 } else {
788 ("Adobe", "Identity", 0)
789 };
790
791 cid_system_info.set("Registry", Object::String(registry.to_string()));
792 cid_system_info.set("Ordering", Object::String(ordering.to_string()));
793 cid_system_info.set("Supplement", Object::Integer(supplement as i64));
794 cid_font.set("CIDSystemInfo", Object::Dictionary(cid_system_info));
795
796 cid_font.set("FontDescriptor", Object::Reference(descriptor_id));
797
798 let default_width = self.calculate_default_width(font);
800 cid_font.set("DW", Object::Integer(default_width));
801
802 let w_array = self.generate_width_array(
806 &original_font_for_widths,
807 default_width,
808 subset_glyph_mapping.as_ref(),
809 );
810 cid_font.set("W", Object::Array(w_array));
811
812 let cid_to_gid_map = self.generate_cid_to_gid_map(font, subset_glyph_mapping.as_ref())?;
816 if !cid_to_gid_map.is_empty() {
817 let cid_to_gid_map_id = self.allocate_object_id();
819 let mut map_dict = Dictionary::new();
820 map_dict.set("Length", Object::Integer(cid_to_gid_map.len() as i64));
821 let map_stream = Object::Stream(map_dict, cid_to_gid_map);
822 self.write_object(cid_to_gid_map_id, map_stream)?;
823 cid_font.set("CIDToGIDMap", Object::Reference(cid_to_gid_map_id));
824 } else {
825 cid_font.set("CIDToGIDMap", Object::Name("Identity".to_string()));
826 }
827
828 self.write_object(descendant_font_id, Object::Dictionary(cid_font))?;
829
830 let cmap_data = self.generate_tounicode_cmap_from_font(font);
832 let cmap_dict = Dictionary::new();
833 let cmap_stream = Object::Stream(cmap_dict, cmap_data);
834 self.write_object(to_unicode_id, cmap_stream)?;
835
836 let mut type0_font = Dictionary::new();
838 type0_font.set("Type", Object::Name("Font".to_string()));
839 type0_font.set("Subtype", Object::Name("Type0".to_string()));
840 type0_font.set("BaseFont", Object::Name(font_name.to_string()));
841 type0_font.set("Encoding", Object::Name("Identity-H".to_string()));
842 type0_font.set(
843 "DescendantFonts",
844 Object::Array(vec![Object::Reference(descendant_font_id)]),
845 );
846 type0_font.set("ToUnicode", Object::Reference(to_unicode_id));
847
848 self.write_object(font_id, Object::Dictionary(type0_font))?;
849
850 Ok(font_id)
851 }
852
853 fn calculate_default_width(&self, font: &crate::fonts::Font) -> i64 {
855 use crate::text::fonts::truetype::TrueTypeFont;
856
857 if let Ok(tt_font) = TrueTypeFont::parse(font.data.clone()) {
859 if let Ok(cmap_tables) = tt_font.parse_cmap() {
860 if let Some(cmap) = cmap_tables
861 .iter()
862 .find(|t| t.platform_id == 3 && t.encoding_id == 1)
863 .or_else(|| cmap_tables.iter().find(|t| t.platform_id == 0))
864 {
865 if let Ok(widths) = tt_font.get_glyph_widths(&cmap.mappings) {
866 let common_chars =
870 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ";
871 let mut total_width = 0;
872 let mut count = 0;
873
874 for ch in common_chars.chars() {
875 let unicode = ch as u32;
876 if let Some(&pdf_width) = widths.get(&unicode) {
877 total_width += pdf_width as i64;
878 count += 1;
879 }
880 }
881
882 if count > 0 {
883 return total_width / count;
884 }
885 }
886 }
887 }
888 }
889
890 500
892 }
893
894 fn generate_width_array(
896 &self,
897 font: &crate::fonts::Font,
898 _default_width: i64,
899 subset_mapping: Option<&HashMap<u32, u16>>,
900 ) -> Vec<Object> {
901 use crate::text::fonts::truetype::TrueTypeFont;
902
903 let mut w_array = Vec::new();
904
905 if let Ok(tt_font) = TrueTypeFont::parse(font.data.clone()) {
907 let char_to_glyph = {
911 if let Ok(cmap_tables) = tt_font.parse_cmap() {
913 if let Some(cmap) = cmap_tables
914 .iter()
915 .find(|t| t.platform_id == 3 && t.encoding_id == 1)
916 .or_else(|| cmap_tables.iter().find(|t| t.platform_id == 0))
917 {
918 if let Some(subset_map) = subset_mapping {
920 let mut filtered = HashMap::new();
921 for unicode in subset_map.keys() {
922 if let Some(&orig_glyph) = cmap.mappings.get(unicode) {
924 filtered.insert(*unicode, orig_glyph);
925 }
926 }
927 filtered
928 } else {
929 cmap.mappings.clone()
930 }
931 } else {
932 HashMap::new()
933 }
934 } else {
935 HashMap::new()
936 }
937 };
938
939 if !char_to_glyph.is_empty() {
940 if let Ok(widths) = tt_font.get_glyph_widths(&char_to_glyph) {
942 let mut sorted_chars: Vec<_> = widths.iter().collect();
947 sorted_chars.sort_by_key(|(unicode, _)| *unicode);
948
949 let mut i = 0;
950 while i < sorted_chars.len() {
951 let start_unicode = *sorted_chars[i].0;
952 let pdf_width = *sorted_chars[i].1 as i64;
954
955 let mut end_unicode = start_unicode;
957 let mut j = i + 1;
958 while j < sorted_chars.len() && *sorted_chars[j].0 == end_unicode + 1 {
959 let next_pdf_width = *sorted_chars[j].1 as i64;
960 if next_pdf_width == pdf_width {
961 end_unicode = *sorted_chars[j].0;
962 j += 1;
963 } else {
964 break;
965 }
966 }
967
968 if start_unicode == end_unicode {
970 w_array.push(Object::Integer(start_unicode as i64));
972 w_array.push(Object::Array(vec![Object::Integer(pdf_width)]));
973 } else {
974 w_array.push(Object::Integer(start_unicode as i64));
976 w_array.push(Object::Integer(end_unicode as i64));
977 w_array.push(Object::Integer(pdf_width));
978 }
979
980 i = j;
981 }
982
983 return w_array;
984 }
985 }
986 }
987
988 let ranges = vec![
990 (0x20, 0x20, 250), (0x21, 0x2F, 333), (0x30, 0x39, 500), (0x3A, 0x40, 333), (0x41, 0x5A, 667), (0x5B, 0x60, 333), (0x61, 0x7A, 500), (0x7B, 0x7E, 333), (0xA0, 0xA0, 250), (0xA1, 0xBF, 333), (0xC0, 0xD6, 667), (0xD7, 0xD7, 564), (0xD8, 0xDE, 667), (0xDF, 0xF6, 500), (0xF7, 0xF7, 564), (0xF8, 0xFF, 500), (0x100, 0x17F, 500), (0x2000, 0x200F, 250), (0x2010, 0x2027, 333), (0x2028, 0x202F, 250), (0x2030, 0x206F, 500), (0x2070, 0x209F, 400), (0x20A0, 0x20CF, 600), (0x2100, 0x214F, 700), (0x2190, 0x21FF, 600), (0x2200, 0x22FF, 600), (0x2300, 0x23FF, 600), (0x2500, 0x257F, 500), (0x2580, 0x259F, 500), (0x25A0, 0x25FF, 600), (0x2600, 0x26FF, 600), (0x2700, 0x27BF, 600), ];
1027
1028 for (start, end, width) in ranges {
1030 if start == end {
1031 w_array.push(Object::Integer(start));
1033 w_array.push(Object::Array(vec![Object::Integer(width)]));
1034 } else {
1035 w_array.push(Object::Integer(start));
1037 w_array.push(Object::Integer(end));
1038 w_array.push(Object::Integer(width));
1039 }
1040 }
1041
1042 w_array
1043 }
1044
1045 fn generate_cid_to_gid_map(
1047 &mut self,
1048 font: &crate::fonts::Font,
1049 subset_mapping: Option<&HashMap<u32, u16>>,
1050 ) -> Result<Vec<u8>> {
1051 use crate::text::fonts::truetype::TrueTypeFont;
1052
1053 let cmap_mappings = if let Some(subset_map) = subset_mapping {
1056 subset_map.clone()
1058 } else {
1059 let tt_font = TrueTypeFont::parse(font.data.clone())?;
1061 let cmap_tables = tt_font.parse_cmap()?;
1062
1063 let cmap = cmap_tables
1065 .iter()
1066 .find(|t| t.platform_id == 3 && t.encoding_id == 1) .or_else(|| cmap_tables.iter().find(|t| t.platform_id == 0)) .ok_or_else(|| {
1069 crate::error::PdfError::FontError("No Unicode cmap table found".to_string())
1070 })?;
1071
1072 cmap.mappings.clone()
1073 };
1074
1075 let used_chars = self.document_used_chars.clone().unwrap_or_default();
1082
1083 let max_unicode = if !used_chars.is_empty() {
1085 used_chars
1087 .iter()
1088 .map(|ch| *ch as u32)
1089 .max()
1090 .unwrap_or(0x00FF) .min(0xFFFF) as usize
1092 } else {
1093 cmap_mappings
1095 .keys()
1096 .max()
1097 .copied()
1098 .unwrap_or(0xFFFF)
1099 .min(0xFFFF) as usize
1100 };
1101
1102 let mut map = vec![0u8; (max_unicode + 1) * 2];
1104
1105 let mut sample_mappings = Vec::new();
1107 for (&unicode, &glyph_id) in &cmap_mappings {
1108 if unicode <= max_unicode as u32 {
1109 let idx = (unicode as usize) * 2;
1110 map[idx] = (glyph_id >> 8) as u8;
1112 map[idx + 1] = (glyph_id & 0xFF) as u8;
1113
1114 if unicode == 0x0041 || unicode == 0x0061 || unicode == 0x00E1 || unicode == 0x00F1
1116 {
1117 sample_mappings.push((unicode, glyph_id));
1118 }
1119 }
1120 }
1121
1122 Ok(map)
1123 }
1124
1125 fn generate_tounicode_cmap_from_font(&self, font: &crate::fonts::Font) -> Vec<u8> {
1127 use crate::text::fonts::truetype::TrueTypeFont;
1128
1129 let mut cmap = String::new();
1130
1131 cmap.push_str("/CIDInit /ProcSet findresource begin\n");
1133 cmap.push_str("12 dict begin\n");
1134 cmap.push_str("begincmap\n");
1135 cmap.push_str("/CIDSystemInfo\n");
1136 cmap.push_str("<< /Registry (Adobe)\n");
1137 cmap.push_str(" /Ordering (UCS)\n");
1138 cmap.push_str(" /Supplement 0\n");
1139 cmap.push_str(">> def\n");
1140 cmap.push_str("/CMapName /Adobe-Identity-UCS def\n");
1141 cmap.push_str("/CMapType 2 def\n");
1142 cmap.push_str("1 begincodespacerange\n");
1143 cmap.push_str("<0000> <FFFF>\n");
1144 cmap.push_str("endcodespacerange\n");
1145
1146 let mut mappings = Vec::new();
1148 let mut has_font_mappings = false;
1149
1150 if let Ok(tt_font) = TrueTypeFont::parse(font.data.clone()) {
1151 if let Ok(cmap_tables) = tt_font.parse_cmap() {
1152 if let Some(cmap_table) = cmap_tables
1154 .iter()
1155 .find(|t| t.platform_id == 3 && t.encoding_id == 1) .or_else(|| cmap_tables.iter().find(|t| t.platform_id == 0))
1157 {
1159 for (&unicode, &glyph_id) in &cmap_table.mappings {
1162 if glyph_id > 0 && unicode <= 0xFFFF {
1163 mappings.push((unicode, unicode));
1166 }
1167 }
1168 has_font_mappings = true;
1169 }
1170 }
1171 }
1172
1173 if !has_font_mappings {
1175 for i in 0x0020..=0x00FF {
1177 mappings.push((i, i));
1178 }
1179
1180 for i in 0x0100..=0x017F {
1182 mappings.push((i, i));
1183 }
1184
1185 for i in 0x3040..=0x309F {
1188 mappings.push((i, i));
1189 }
1190
1191 for i in 0x30A0..=0x30FF {
1193 mappings.push((i, i));
1194 }
1195
1196 for i in 0x4E00..=0x9FFF {
1198 mappings.push((i, i));
1199 }
1200
1201 for i in 0xAC00..=0xD7AF {
1203 mappings.push((i, i));
1204 }
1205
1206 for i in 0x2000..=0x206F {
1208 mappings.push((i, i));
1209 }
1210
1211 for i in 0x2200..=0x22FF {
1213 mappings.push((i, i));
1214 }
1215
1216 for i in 0x2190..=0x21FF {
1218 mappings.push((i, i));
1219 }
1220
1221 for i in 0x2500..=0x259F {
1223 mappings.push((i, i));
1224 }
1225
1226 for i in 0x25A0..=0x25FF {
1228 mappings.push((i, i));
1229 }
1230
1231 for i in 0x2600..=0x26FF {
1233 mappings.push((i, i));
1234 }
1235 }
1236
1237 mappings.sort_by_key(|&(cid, _)| cid);
1239
1240 let mut i = 0;
1242 while i < mappings.len() {
1243 let start_cid = mappings[i].0;
1245 let start_unicode = mappings[i].1;
1246 let mut end_idx = i;
1247
1248 while end_idx + 1 < mappings.len()
1250 && mappings[end_idx + 1].0 == mappings[end_idx].0 + 1
1251 && mappings[end_idx + 1].1 == mappings[end_idx].1 + 1
1252 && end_idx - i < 99
1253 {
1255 end_idx += 1;
1256 }
1257
1258 if end_idx > i {
1259 cmap.push_str("1 beginbfrange\n");
1261 cmap.push_str(&format!(
1262 "<{:04X}> <{:04X}> <{:04X}>\n",
1263 start_cid, mappings[end_idx].0, start_unicode
1264 ));
1265 cmap.push_str("endbfrange\n");
1266 i = end_idx + 1;
1267 } else {
1268 let mut chars = Vec::new();
1270 let chunk_end = (i + 100).min(mappings.len());
1271
1272 for item in &mappings[i..chunk_end] {
1273 chars.push(*item);
1274 }
1275
1276 if !chars.is_empty() {
1277 cmap.push_str(&format!("{} beginbfchar\n", chars.len()));
1278 for (cid, unicode) in chars {
1279 cmap.push_str(&format!("<{:04X}> <{:04X}>\n", cid, unicode));
1280 }
1281 cmap.push_str("endbfchar\n");
1282 }
1283
1284 i = chunk_end;
1285 }
1286 }
1287
1288 cmap.push_str("endcmap\n");
1290 cmap.push_str("CMapName currentdict /CMap defineresource pop\n");
1291 cmap.push_str("end\n");
1292 cmap.push_str("end\n");
1293
1294 cmap.into_bytes()
1295 }
1296
1297 #[allow(dead_code)]
1299 fn write_truetype_font(
1300 &mut self,
1301 font_name: &str,
1302 font: &crate::text::font_manager::CustomFont,
1303 ) -> Result<ObjectId> {
1304 let font_id = self.allocate_object_id();
1306 let descriptor_id = self.allocate_object_id();
1307 let font_file_id = self.allocate_object_id();
1308
1309 if let Some(ref data) = font.font_data {
1311 let mut font_file_dict = Dictionary::new();
1312 font_file_dict.set("Length1", Object::Integer(data.len() as i64));
1313 let font_stream_obj = Object::Stream(font_file_dict, data.clone());
1314 self.write_object(font_file_id, font_stream_obj)?;
1315 }
1316
1317 let mut descriptor = Dictionary::new();
1319 descriptor.set("Type", Object::Name("FontDescriptor".to_string()));
1320 descriptor.set("FontName", Object::Name(font_name.to_string()));
1321 descriptor.set("Flags", Object::Integer(32)); descriptor.set(
1323 "FontBBox",
1324 Object::Array(vec![
1325 Object::Integer(-1000),
1326 Object::Integer(-1000),
1327 Object::Integer(2000),
1328 Object::Integer(2000),
1329 ]),
1330 );
1331 descriptor.set("ItalicAngle", Object::Integer(0));
1332 descriptor.set("Ascent", Object::Integer(font.descriptor.ascent as i64));
1333 descriptor.set("Descent", Object::Integer(font.descriptor.descent as i64));
1334 descriptor.set(
1335 "CapHeight",
1336 Object::Integer(font.descriptor.cap_height as i64),
1337 );
1338 descriptor.set("StemV", Object::Integer(font.descriptor.stem_v as i64));
1339 descriptor.set("FontFile2", Object::Reference(font_file_id));
1340 self.write_object(descriptor_id, Object::Dictionary(descriptor))?;
1341
1342 let mut font_dict = Dictionary::new();
1344 font_dict.set("Type", Object::Name("Font".to_string()));
1345 font_dict.set("Subtype", Object::Name("TrueType".to_string()));
1346 font_dict.set("BaseFont", Object::Name(font_name.to_string()));
1347 font_dict.set("FirstChar", Object::Integer(0));
1348 font_dict.set("LastChar", Object::Integer(255));
1349
1350 let widths: Vec<Object> = (0..256).map(|_| Object::Integer(600)).collect();
1352 font_dict.set("Widths", Object::Array(widths));
1353 font_dict.set("FontDescriptor", Object::Reference(descriptor_id));
1354
1355 font_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
1357
1358 self.write_object(font_id, Object::Dictionary(font_dict))?;
1359
1360 Ok(font_id)
1361 }
1362
1363 fn write_pages(
1364 &mut self,
1365 document: &Document,
1366 font_refs: &HashMap<String, ObjectId>,
1367 ) -> Result<()> {
1368 let pages_id = self.pages_id.expect("pages_id must be set");
1369 let mut pages_dict = Dictionary::new();
1370 pages_dict.set("Type", Object::Name("Pages".to_string()));
1371 pages_dict.set("Count", Object::Integer(document.pages.len() as i64));
1372
1373 let mut kids = Vec::new();
1374
1375 let mut page_ids = Vec::new();
1377 let mut content_ids = Vec::new();
1378 for _ in 0..document.pages.len() {
1379 page_ids.push(self.allocate_object_id());
1380 content_ids.push(self.allocate_object_id());
1381 }
1382
1383 for page_id in &page_ids {
1384 kids.push(Object::Reference(*page_id));
1385 }
1386
1387 pages_dict.set("Kids", Object::Array(kids));
1388
1389 self.write_object(pages_id, Object::Dictionary(pages_dict))?;
1390
1391 self.page_ids = page_ids.clone();
1393
1394 for (i, page) in document.pages.iter().enumerate() {
1396 let page_id = page_ids[i];
1397 let content_id = content_ids[i];
1398
1399 self.write_page_with_fonts(page_id, pages_id, content_id, page, document, font_refs)?;
1400 self.write_page_content(content_id, page)?;
1401 }
1402
1403 Ok(())
1404 }
1405
1406 #[allow(dead_code)]
1408 fn write_pages_with_fonts(
1409 &mut self,
1410 document: &Document,
1411 font_refs: &HashMap<String, ObjectId>,
1412 ) -> Result<()> {
1413 self.write_pages(document, font_refs)
1414 }
1415
1416 fn write_page_with_fonts(
1417 &mut self,
1418 page_id: ObjectId,
1419 parent_id: ObjectId,
1420 content_id: ObjectId,
1421 page: &crate::page::Page,
1422 _document: &Document,
1423 font_refs: &HashMap<String, ObjectId>,
1424 ) -> Result<()> {
1425 let mut page_dict = page.to_dict();
1427
1428 page_dict.set("Type", Object::Name("Page".to_string()));
1429 page_dict.set("Parent", Object::Reference(parent_id));
1430 page_dict.set("Contents", Object::Reference(content_id));
1431
1432 let mut resources = if let Some(Object::Dictionary(res)) = page_dict.get("Resources") {
1434 res.clone()
1435 } else {
1436 Dictionary::new()
1437 };
1438
1439 let mut font_dict = Dictionary::new();
1441
1442 let mut helvetica_dict = Dictionary::new();
1447 helvetica_dict.set("Type", Object::Name("Font".to_string()));
1448 helvetica_dict.set("Subtype", Object::Name("Type1".to_string()));
1449 helvetica_dict.set("BaseFont", Object::Name("Helvetica".to_string()));
1450 helvetica_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
1451 font_dict.set("Helvetica", Object::Dictionary(helvetica_dict));
1452
1453 let mut helvetica_bold_dict = Dictionary::new();
1454 helvetica_bold_dict.set("Type", Object::Name("Font".to_string()));
1455 helvetica_bold_dict.set("Subtype", Object::Name("Type1".to_string()));
1456 helvetica_bold_dict.set("BaseFont", Object::Name("Helvetica-Bold".to_string()));
1457 helvetica_bold_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
1458 font_dict.set("Helvetica-Bold", Object::Dictionary(helvetica_bold_dict));
1459
1460 let mut helvetica_oblique_dict = Dictionary::new();
1461 helvetica_oblique_dict.set("Type", Object::Name("Font".to_string()));
1462 helvetica_oblique_dict.set("Subtype", Object::Name("Type1".to_string()));
1463 helvetica_oblique_dict.set("BaseFont", Object::Name("Helvetica-Oblique".to_string()));
1464 helvetica_oblique_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
1465 font_dict.set(
1466 "Helvetica-Oblique",
1467 Object::Dictionary(helvetica_oblique_dict),
1468 );
1469
1470 let mut helvetica_bold_oblique_dict = Dictionary::new();
1471 helvetica_bold_oblique_dict.set("Type", Object::Name("Font".to_string()));
1472 helvetica_bold_oblique_dict.set("Subtype", Object::Name("Type1".to_string()));
1473 helvetica_bold_oblique_dict.set(
1474 "BaseFont",
1475 Object::Name("Helvetica-BoldOblique".to_string()),
1476 );
1477 helvetica_bold_oblique_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
1478 font_dict.set(
1479 "Helvetica-BoldOblique",
1480 Object::Dictionary(helvetica_bold_oblique_dict),
1481 );
1482
1483 let mut times_dict = Dictionary::new();
1485 times_dict.set("Type", Object::Name("Font".to_string()));
1486 times_dict.set("Subtype", Object::Name("Type1".to_string()));
1487 times_dict.set("BaseFont", Object::Name("Times-Roman".to_string()));
1488 times_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
1489 font_dict.set("Times-Roman", Object::Dictionary(times_dict));
1490
1491 let mut times_bold_dict = Dictionary::new();
1492 times_bold_dict.set("Type", Object::Name("Font".to_string()));
1493 times_bold_dict.set("Subtype", Object::Name("Type1".to_string()));
1494 times_bold_dict.set("BaseFont", Object::Name("Times-Bold".to_string()));
1495 times_bold_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
1496 font_dict.set("Times-Bold", Object::Dictionary(times_bold_dict));
1497
1498 let mut times_italic_dict = Dictionary::new();
1499 times_italic_dict.set("Type", Object::Name("Font".to_string()));
1500 times_italic_dict.set("Subtype", Object::Name("Type1".to_string()));
1501 times_italic_dict.set("BaseFont", Object::Name("Times-Italic".to_string()));
1502 times_italic_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
1503 font_dict.set("Times-Italic", Object::Dictionary(times_italic_dict));
1504
1505 let mut times_bold_italic_dict = Dictionary::new();
1506 times_bold_italic_dict.set("Type", Object::Name("Font".to_string()));
1507 times_bold_italic_dict.set("Subtype", Object::Name("Type1".to_string()));
1508 times_bold_italic_dict.set("BaseFont", Object::Name("Times-BoldItalic".to_string()));
1509 times_bold_italic_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
1510 font_dict.set(
1511 "Times-BoldItalic",
1512 Object::Dictionary(times_bold_italic_dict),
1513 );
1514
1515 let mut courier_dict = Dictionary::new();
1517 courier_dict.set("Type", Object::Name("Font".to_string()));
1518 courier_dict.set("Subtype", Object::Name("Type1".to_string()));
1519 courier_dict.set("BaseFont", Object::Name("Courier".to_string()));
1520 courier_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
1521 font_dict.set("Courier", Object::Dictionary(courier_dict));
1522
1523 let mut courier_bold_dict = Dictionary::new();
1524 courier_bold_dict.set("Type", Object::Name("Font".to_string()));
1525 courier_bold_dict.set("Subtype", Object::Name("Type1".to_string()));
1526 courier_bold_dict.set("BaseFont", Object::Name("Courier-Bold".to_string()));
1527 courier_bold_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
1528 font_dict.set("Courier-Bold", Object::Dictionary(courier_bold_dict));
1529
1530 let mut courier_oblique_dict = Dictionary::new();
1531 courier_oblique_dict.set("Type", Object::Name("Font".to_string()));
1532 courier_oblique_dict.set("Subtype", Object::Name("Type1".to_string()));
1533 courier_oblique_dict.set("BaseFont", Object::Name("Courier-Oblique".to_string()));
1534 courier_oblique_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
1535 font_dict.set("Courier-Oblique", Object::Dictionary(courier_oblique_dict));
1536
1537 let mut courier_bold_oblique_dict = Dictionary::new();
1538 courier_bold_oblique_dict.set("Type", Object::Name("Font".to_string()));
1539 courier_bold_oblique_dict.set("Subtype", Object::Name("Type1".to_string()));
1540 courier_bold_oblique_dict.set("BaseFont", Object::Name("Courier-BoldOblique".to_string()));
1541 courier_bold_oblique_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
1542 font_dict.set(
1543 "Courier-BoldOblique",
1544 Object::Dictionary(courier_bold_oblique_dict),
1545 );
1546
1547 for (font_name, font_id) in font_refs {
1549 font_dict.set(font_name, Object::Reference(*font_id));
1550 }
1551
1552 resources.set("Font", Object::Dictionary(font_dict));
1553
1554 if !page.images().is_empty() {
1556 let mut xobject_dict = Dictionary::new();
1557
1558 for (name, image) in page.images() {
1559 let image_id = self.allocate_object_id();
1561
1562 if image.has_transparency() {
1564 let (mut main_obj, smask_obj) = image.to_pdf_object_with_transparency();
1566
1567 if let Some(smask_stream) = smask_obj {
1569 let smask_id = self.allocate_object_id();
1570 self.write_object(smask_id, smask_stream)?;
1571
1572 if let Object::Stream(ref mut dict, _) = main_obj {
1574 dict.set("SMask", Object::Reference(smask_id));
1575 }
1576 }
1577
1578 self.write_object(image_id, main_obj)?;
1580 } else {
1581 self.write_object(image_id, image.to_pdf_object())?;
1583 }
1584
1585 xobject_dict.set(name, Object::Reference(image_id));
1587 }
1588
1589 resources.set("XObject", Object::Dictionary(xobject_dict));
1590 }
1591
1592 if let Some(extgstate_states) = page.get_extgstate_resources() {
1594 let mut extgstate_dict = Dictionary::new();
1595 for (name, state) in extgstate_states {
1596 let mut state_dict = Dictionary::new();
1597 state_dict.set("Type", Object::Name("ExtGState".to_string()));
1598
1599 if let Some(alpha_stroke) = state.alpha_stroke {
1601 state_dict.set("CA", Object::Real(alpha_stroke));
1602 }
1603 if let Some(alpha_fill) = state.alpha_fill {
1604 state_dict.set("ca", Object::Real(alpha_fill));
1605 }
1606
1607 if let Some(line_width) = state.line_width {
1609 state_dict.set("LW", Object::Real(line_width));
1610 }
1611 if let Some(line_cap) = state.line_cap {
1612 state_dict.set("LC", Object::Integer(line_cap as i64));
1613 }
1614 if let Some(line_join) = state.line_join {
1615 state_dict.set("LJ", Object::Integer(line_join as i64));
1616 }
1617 if let Some(dash_pattern) = &state.dash_pattern {
1618 let dash_objects: Vec<Object> = dash_pattern
1619 .array
1620 .iter()
1621 .map(|&d| Object::Real(d))
1622 .collect();
1623 state_dict.set(
1624 "D",
1625 Object::Array(vec![
1626 Object::Array(dash_objects),
1627 Object::Real(dash_pattern.phase),
1628 ]),
1629 );
1630 }
1631
1632 extgstate_dict.set(name, Object::Dictionary(state_dict));
1633 }
1634 if !extgstate_dict.is_empty() {
1635 resources.set("ExtGState", Object::Dictionary(extgstate_dict));
1636 }
1637 }
1638
1639 page_dict.set("Resources", Object::Dictionary(resources));
1640
1641 if let Some(Object::Array(annots)) = page_dict.get("Annots") {
1643 let mut new_annots = Vec::new();
1644
1645 for annot in annots {
1646 if let Object::Dictionary(ref annot_dict) = annot {
1647 if let Some(Object::Name(subtype)) = annot_dict.get("Subtype") {
1648 if subtype == "Widget" {
1649 let widget_id = self.allocate_object_id();
1651 self.write_object(widget_id, annot.clone())?;
1652 new_annots.push(Object::Reference(widget_id));
1653
1654 if let Some(Object::Name(_ft)) = annot_dict.get("FT") {
1656 if let Some(Object::String(field_name)) = annot_dict.get("T") {
1657 self.field_widget_map
1658 .entry(field_name.clone())
1659 .or_default()
1660 .push(widget_id);
1661 self.field_id_map.insert(field_name.clone(), widget_id);
1662 self.form_field_ids.push(widget_id);
1663 }
1664 }
1665 continue;
1666 }
1667 }
1668 }
1669 new_annots.push(annot.clone());
1670 }
1671
1672 if !new_annots.is_empty() {
1673 page_dict.set("Annots", Object::Array(new_annots));
1674 }
1675 }
1676
1677 self.write_object(page_id, Object::Dictionary(page_dict))?;
1678 Ok(())
1679 }
1680}
1681
1682impl PdfWriter<BufWriter<std::fs::File>> {
1683 pub fn new(path: impl AsRef<Path>) -> Result<Self> {
1684 let file = std::fs::File::create(path)?;
1685 let writer = BufWriter::new(file);
1686
1687 Ok(Self {
1688 writer,
1689 xref_positions: HashMap::new(),
1690 current_position: 0,
1691 next_object_id: 1,
1692 catalog_id: None,
1693 pages_id: None,
1694 info_id: None,
1695 field_widget_map: HashMap::new(),
1696 field_id_map: HashMap::new(),
1697 form_field_ids: Vec::new(),
1698 page_ids: Vec::new(),
1699 config: WriterConfig::default(),
1700 document_used_chars: None,
1701 buffered_objects: HashMap::new(),
1702 compressed_object_map: HashMap::new(),
1703 })
1704 }
1705}
1706
1707impl<W: Write> PdfWriter<W> {
1708 fn allocate_object_id(&mut self) -> ObjectId {
1709 let id = ObjectId::new(self.next_object_id, 0);
1710 self.next_object_id += 1;
1711 id
1712 }
1713
1714 fn write_object(&mut self, id: ObjectId, object: Object) -> Result<()> {
1715 use crate::writer::ObjectStreamWriter;
1716
1717 if self.config.use_object_streams && ObjectStreamWriter::can_compress(&object) {
1719 let mut buffer = Vec::new();
1720 self.write_object_value_to_buffer(&object, &mut buffer)?;
1721 self.buffered_objects.insert(id, buffer);
1722 return Ok(());
1723 }
1724
1725 self.xref_positions.insert(id, self.current_position);
1727
1728 let header = format!("{} {} obj\n", id.number(), id.generation());
1730 self.write_bytes(header.as_bytes())?;
1731
1732 self.write_object_value(&object)?;
1733
1734 self.write_bytes(b"\nendobj\n")?;
1735 Ok(())
1736 }
1737
1738 fn write_object_value(&mut self, object: &Object) -> Result<()> {
1739 match object {
1740 Object::Null => self.write_bytes(b"null")?,
1741 Object::Boolean(b) => self.write_bytes(if *b { b"true" } else { b"false" })?,
1742 Object::Integer(i) => self.write_bytes(i.to_string().as_bytes())?,
1743 Object::Real(f) => self.write_bytes(
1744 format!("{f:.6}")
1745 .trim_end_matches('0')
1746 .trim_end_matches('.')
1747 .as_bytes(),
1748 )?,
1749 Object::String(s) => {
1750 self.write_bytes(b"(")?;
1751 self.write_bytes(s.as_bytes())?;
1752 self.write_bytes(b")")?;
1753 }
1754 Object::Name(n) => {
1755 self.write_bytes(b"/")?;
1756 self.write_bytes(n.as_bytes())?;
1757 }
1758 Object::Array(arr) => {
1759 self.write_bytes(b"[")?;
1760 for (i, obj) in arr.iter().enumerate() {
1761 if i > 0 {
1762 self.write_bytes(b" ")?;
1763 }
1764 self.write_object_value(obj)?;
1765 }
1766 self.write_bytes(b"]")?;
1767 }
1768 Object::Dictionary(dict) => {
1769 self.write_bytes(b"<<")?;
1770 for (key, value) in dict.entries() {
1771 self.write_bytes(b"\n/")?;
1772 self.write_bytes(key.as_bytes())?;
1773 self.write_bytes(b" ")?;
1774 self.write_object_value(value)?;
1775 }
1776 self.write_bytes(b"\n>>")?;
1777 }
1778 Object::Stream(dict, data) => {
1779 self.write_object_value(&Object::Dictionary(dict.clone()))?;
1780 self.write_bytes(b"\nstream\n")?;
1781 self.write_bytes(data)?;
1782 self.write_bytes(b"\nendstream")?;
1783 }
1784 Object::Reference(id) => {
1785 let ref_str = format!("{} {} R", id.number(), id.generation());
1786 self.write_bytes(ref_str.as_bytes())?;
1787 }
1788 }
1789 Ok(())
1790 }
1791
1792 fn write_object_value_to_buffer(&self, object: &Object, buffer: &mut Vec<u8>) -> Result<()> {
1794 match object {
1795 Object::Null => buffer.extend_from_slice(b"null"),
1796 Object::Boolean(b) => buffer.extend_from_slice(if *b { b"true" } else { b"false" }),
1797 Object::Integer(i) => buffer.extend_from_slice(i.to_string().as_bytes()),
1798 Object::Real(f) => buffer.extend_from_slice(
1799 format!("{f:.6}")
1800 .trim_end_matches('0')
1801 .trim_end_matches('.')
1802 .as_bytes(),
1803 ),
1804 Object::String(s) => {
1805 buffer.push(b'(');
1806 buffer.extend_from_slice(s.as_bytes());
1807 buffer.push(b')');
1808 }
1809 Object::Name(n) => {
1810 buffer.push(b'/');
1811 buffer.extend_from_slice(n.as_bytes());
1812 }
1813 Object::Array(arr) => {
1814 buffer.push(b'[');
1815 for (i, obj) in arr.iter().enumerate() {
1816 if i > 0 {
1817 buffer.push(b' ');
1818 }
1819 self.write_object_value_to_buffer(obj, buffer)?;
1820 }
1821 buffer.push(b']');
1822 }
1823 Object::Dictionary(dict) => {
1824 buffer.extend_from_slice(b"<<");
1825 for (key, value) in dict.entries() {
1826 buffer.extend_from_slice(b"\n/");
1827 buffer.extend_from_slice(key.as_bytes());
1828 buffer.push(b' ');
1829 self.write_object_value_to_buffer(value, buffer)?;
1830 }
1831 buffer.extend_from_slice(b"\n>>");
1832 }
1833 Object::Stream(_, _) => {
1834 return Err(crate::error::PdfError::ObjectStreamError(
1836 "Cannot compress stream objects in object streams".to_string(),
1837 ));
1838 }
1839 Object::Reference(id) => {
1840 let ref_str = format!("{} {} R", id.number(), id.generation());
1841 buffer.extend_from_slice(ref_str.as_bytes());
1842 }
1843 }
1844 Ok(())
1845 }
1846
1847 fn flush_object_streams(&mut self) -> Result<()> {
1849 if self.buffered_objects.is_empty() {
1850 return Ok(());
1851 }
1852
1853 let config = ObjectStreamConfig {
1855 max_objects_per_stream: 100,
1856 compression_level: 6,
1857 enabled: true,
1858 };
1859 let mut os_writer = ObjectStreamWriter::new(config);
1860
1861 let mut buffered: Vec<_> = self.buffered_objects.iter().collect();
1863 buffered.sort_by_key(|(id, _)| id.number());
1864
1865 for (id, data) in buffered {
1867 os_writer.add_object(*id, data.clone())?;
1868 }
1869
1870 let streams = os_writer.finalize()?;
1872
1873 for mut stream in streams {
1875 let stream_id = stream.stream_id;
1876
1877 let compressed_data = stream.generate_stream_data(6)?;
1879
1880 let dict = stream.generate_dictionary(&compressed_data);
1882
1883 for (index, (obj_id, _)) in stream.objects.iter().enumerate() {
1885 self.compressed_object_map
1886 .insert(*obj_id, (stream_id, index as u32));
1887 }
1888
1889 self.xref_positions.insert(stream_id, self.current_position);
1891
1892 let header = format!("{} {} obj\n", stream_id.number(), stream_id.generation());
1893 self.write_bytes(header.as_bytes())?;
1894
1895 self.write_object_value(&Object::Dictionary(dict))?;
1896
1897 self.write_bytes(b"\nstream\n")?;
1898 self.write_bytes(&compressed_data)?;
1899 self.write_bytes(b"\nendstream\nendobj\n")?;
1900 }
1901
1902 Ok(())
1903 }
1904
1905 fn write_xref(&mut self) -> Result<()> {
1906 self.write_bytes(b"xref\n")?;
1907
1908 let mut entries: Vec<_> = self
1910 .xref_positions
1911 .iter()
1912 .map(|(id, pos)| (*id, *pos))
1913 .collect();
1914 entries.sort_by_key(|(id, _)| id.number());
1915
1916 let max_obj_num = entries.iter().map(|(id, _)| id.number()).max().unwrap_or(0);
1918
1919 self.write_bytes(b"0 ")?;
1922 self.write_bytes((max_obj_num + 1).to_string().as_bytes())?;
1923 self.write_bytes(b"\n")?;
1924
1925 self.write_bytes(b"0000000000 65535 f \n")?;
1927
1928 for obj_num in 1..=max_obj_num {
1931 let _obj_id = ObjectId::new(obj_num, 0);
1932 if let Some((_, position)) = entries.iter().find(|(id, _)| id.number() == obj_num) {
1933 let entry = format!("{:010} {:05} n \n", position, 0);
1934 self.write_bytes(entry.as_bytes())?;
1935 } else {
1936 self.write_bytes(b"0000000000 00000 f \n")?;
1938 }
1939 }
1940
1941 Ok(())
1942 }
1943
1944 fn write_xref_stream(&mut self) -> Result<()> {
1945 let catalog_id = self.catalog_id.expect("catalog_id must be set");
1946 let info_id = self.info_id.expect("info_id must be set");
1947
1948 let xref_stream_id = self.allocate_object_id();
1950 let xref_position = self.current_position;
1951
1952 let mut xref_writer = XRefStreamWriter::new(xref_stream_id);
1954 xref_writer.set_trailer_info(catalog_id, info_id);
1955
1956 xref_writer.add_free_entry(0, 65535);
1958
1959 let mut entries: Vec<_> = self
1961 .xref_positions
1962 .iter()
1963 .map(|(id, pos)| (*id, *pos))
1964 .collect();
1965 entries.sort_by_key(|(id, _)| id.number());
1966
1967 let max_obj_num = entries
1969 .iter()
1970 .map(|(id, _)| id.number())
1971 .max()
1972 .unwrap_or(0)
1973 .max(xref_stream_id.number());
1974
1975 for obj_num in 1..=max_obj_num {
1977 let obj_id = ObjectId::new(obj_num, 0);
1978
1979 if obj_num == xref_stream_id.number() {
1980 xref_writer.add_in_use_entry(xref_position, 0);
1982 } else if let Some((stream_id, index)) = self.compressed_object_map.get(&obj_id) {
1983 xref_writer.add_compressed_entry(stream_id.number(), *index);
1985 } else if let Some((id, position)) =
1986 entries.iter().find(|(id, _)| id.number() == obj_num)
1987 {
1988 xref_writer.add_in_use_entry(*position, id.generation());
1990 } else {
1991 xref_writer.add_free_entry(0, 0);
1993 }
1994 }
1995
1996 self.xref_positions.insert(xref_stream_id, xref_position);
1998
1999 self.write_bytes(
2001 format!(
2002 "{} {} obj\n",
2003 xref_stream_id.number(),
2004 xref_stream_id.generation()
2005 )
2006 .as_bytes(),
2007 )?;
2008
2009 let uncompressed_data = xref_writer.encode_entries();
2011 let final_data = if self.config.compress_streams {
2012 crate::compression::compress(&uncompressed_data)?
2013 } else {
2014 uncompressed_data
2015 };
2016
2017 let mut dict = xref_writer.create_dictionary(None);
2019 dict.set("Length", Object::Integer(final_data.len() as i64));
2020
2021 if self.config.compress_streams {
2023 dict.set("Filter", Object::Name("FlateDecode".to_string()));
2024 }
2025 self.write_bytes(b"<<")?;
2026 for (key, value) in dict.iter() {
2027 self.write_bytes(b"\n/")?;
2028 self.write_bytes(key.as_bytes())?;
2029 self.write_bytes(b" ")?;
2030 self.write_object_value(value)?;
2031 }
2032 self.write_bytes(b"\n>>\n")?;
2033
2034 self.write_bytes(b"stream\n")?;
2036 self.write_bytes(&final_data)?;
2037 self.write_bytes(b"\nendstream\n")?;
2038 self.write_bytes(b"endobj\n")?;
2039
2040 self.write_bytes(b"\nstartxref\n")?;
2042 self.write_bytes(xref_position.to_string().as_bytes())?;
2043 self.write_bytes(b"\n%%EOF\n")?;
2044
2045 Ok(())
2046 }
2047
2048 fn write_trailer(&mut self, xref_position: u64) -> Result<()> {
2049 let catalog_id = self.catalog_id.expect("catalog_id must be set");
2050 let info_id = self.info_id.expect("info_id must be set");
2051 let max_obj_num = self
2053 .xref_positions
2054 .keys()
2055 .map(|id| id.number())
2056 .max()
2057 .unwrap_or(0);
2058
2059 let mut trailer = Dictionary::new();
2060 trailer.set("Size", Object::Integer((max_obj_num + 1) as i64));
2061 trailer.set("Root", Object::Reference(catalog_id));
2062 trailer.set("Info", Object::Reference(info_id));
2063
2064 self.write_bytes(b"trailer\n")?;
2065 self.write_object_value(&Object::Dictionary(trailer))?;
2066 self.write_bytes(b"\nstartxref\n")?;
2067 self.write_bytes(xref_position.to_string().as_bytes())?;
2068 self.write_bytes(b"\n%%EOF\n")?;
2069
2070 Ok(())
2071 }
2072
2073 fn write_bytes(&mut self, data: &[u8]) -> Result<()> {
2074 self.writer.write_all(data)?;
2075 self.current_position += data.len() as u64;
2076 Ok(())
2077 }
2078
2079 #[allow(dead_code)]
2080 fn create_widget_appearance_stream(&mut self, widget_dict: &Dictionary) -> Result<ObjectId> {
2081 let rect = if let Some(Object::Array(rect_array)) = widget_dict.get("Rect") {
2083 if rect_array.len() >= 4 {
2084 if let (
2085 Some(Object::Real(x1)),
2086 Some(Object::Real(y1)),
2087 Some(Object::Real(x2)),
2088 Some(Object::Real(y2)),
2089 ) = (
2090 rect_array.first(),
2091 rect_array.get(1),
2092 rect_array.get(2),
2093 rect_array.get(3),
2094 ) {
2095 (*x1, *y1, *x2, *y2)
2096 } else {
2097 (0.0, 0.0, 100.0, 20.0) }
2099 } else {
2100 (0.0, 0.0, 100.0, 20.0) }
2102 } else {
2103 (0.0, 0.0, 100.0, 20.0) };
2105
2106 let width = rect.2 - rect.0;
2107 let height = rect.3 - rect.1;
2108
2109 let mut content = String::new();
2111
2112 content.push_str("q\n");
2114
2115 content.push_str("0 0 0 RG\n"); content.push_str("1 w\n"); content.push_str(&format!("0 0 {width} {height} re\n"));
2121 content.push_str("S\n"); content.push_str("1 1 1 rg\n"); content.push_str(&format!("0.5 0.5 {} {} re\n", width - 1.0, height - 1.0));
2126 content.push_str("f\n"); content.push_str("Q\n");
2130
2131 let mut stream_dict = Dictionary::new();
2133 stream_dict.set("Type", Object::Name("XObject".to_string()));
2134 stream_dict.set("Subtype", Object::Name("Form".to_string()));
2135 stream_dict.set(
2136 "BBox",
2137 Object::Array(vec![
2138 Object::Real(0.0),
2139 Object::Real(0.0),
2140 Object::Real(width),
2141 Object::Real(height),
2142 ]),
2143 );
2144 stream_dict.set("Resources", Object::Dictionary(Dictionary::new()));
2145 stream_dict.set("Length", Object::Integer(content.len() as i64));
2146
2147 let stream_id = self.allocate_object_id();
2149 self.write_object(stream_id, Object::Stream(stream_dict, content.into_bytes()))?;
2150
2151 Ok(stream_id)
2152 }
2153
2154 #[allow(dead_code)]
2155 fn create_field_appearance_stream(
2156 &mut self,
2157 field_dict: &Dictionary,
2158 widget: &crate::forms::Widget,
2159 ) -> Result<ObjectId> {
2160 let width = widget.rect.upper_right.x - widget.rect.lower_left.x;
2161 let height = widget.rect.upper_right.y - widget.rect.lower_left.y;
2162
2163 let mut content = String::new();
2165
2166 content.push_str("q\n");
2168
2169 if let Some(bg_color) = &widget.appearance.background_color {
2171 match bg_color {
2172 crate::graphics::Color::Gray(g) => {
2173 content.push_str(&format!("{g} g\n"));
2174 }
2175 crate::graphics::Color::Rgb(r, g, b) => {
2176 content.push_str(&format!("{r} {g} {b} rg\n"));
2177 }
2178 crate::graphics::Color::Cmyk(c, m, y, k) => {
2179 content.push_str(&format!("{c} {m} {y} {k} k\n"));
2180 }
2181 }
2182 content.push_str(&format!("0 0 {width} {height} re\n"));
2183 content.push_str("f\n");
2184 }
2185
2186 if let Some(border_color) = &widget.appearance.border_color {
2188 match border_color {
2189 crate::graphics::Color::Gray(g) => {
2190 content.push_str(&format!("{g} G\n"));
2191 }
2192 crate::graphics::Color::Rgb(r, g, b) => {
2193 content.push_str(&format!("{r} {g} {b} RG\n"));
2194 }
2195 crate::graphics::Color::Cmyk(c, m, y, k) => {
2196 content.push_str(&format!("{c} {m} {y} {k} K\n"));
2197 }
2198 }
2199 content.push_str(&format!("{} w\n", widget.appearance.border_width));
2200 content.push_str(&format!("0 0 {width} {height} re\n"));
2201 content.push_str("S\n");
2202 }
2203
2204 if let Some(Object::Name(ft)) = field_dict.get("FT") {
2206 if ft == "Btn" {
2207 if let Some(Object::Name(v)) = field_dict.get("V") {
2208 if v == "Yes" {
2209 content.push_str("0 0 0 RG\n"); content.push_str("2 w\n");
2212 let margin = width * 0.2;
2213 content.push_str(&format!("{} {} m\n", margin, height / 2.0));
2214 content.push_str(&format!("{} {} l\n", width / 2.0, margin));
2215 content.push_str(&format!("{} {} l\n", width - margin, height - margin));
2216 content.push_str("S\n");
2217 }
2218 }
2219 }
2220 }
2221
2222 content.push_str("Q\n");
2224
2225 let mut stream_dict = Dictionary::new();
2227 stream_dict.set("Type", Object::Name("XObject".to_string()));
2228 stream_dict.set("Subtype", Object::Name("Form".to_string()));
2229 stream_dict.set(
2230 "BBox",
2231 Object::Array(vec![
2232 Object::Real(0.0),
2233 Object::Real(0.0),
2234 Object::Real(width),
2235 Object::Real(height),
2236 ]),
2237 );
2238 stream_dict.set("Resources", Object::Dictionary(Dictionary::new()));
2239 stream_dict.set("Length", Object::Integer(content.len() as i64));
2240
2241 let stream_id = self.allocate_object_id();
2243 self.write_object(stream_id, Object::Stream(stream_dict, content.into_bytes()))?;
2244
2245 Ok(stream_id)
2246 }
2247}
2248
2249fn format_pdf_date(date: DateTime<Utc>) -> String {
2251 let formatted = date.format("D:%Y%m%d%H%M%S");
2254
2255 format!("{formatted}+00'00")
2257}
2258
2259#[cfg(test)]
2260mod tests;
2261
2262#[cfg(test)]
2263mod rigorous_tests;