1use crate::document::Document;
2use crate::error::{PdfError, 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 pub incremental_update: bool,
24}
25
26impl Default for WriterConfig {
27 fn default() -> Self {
28 Self {
29 use_xref_streams: false,
30 use_object_streams: false,
31 pdf_version: "1.7".to_string(),
32 compress_streams: true,
33 incremental_update: false,
34 }
35 }
36}
37
38impl WriterConfig {
39 pub fn modern() -> Self {
41 Self {
42 use_xref_streams: true,
43 use_object_streams: true,
44 pdf_version: "1.5".to_string(),
45 compress_streams: true,
46 incremental_update: false,
47 }
48 }
49
50 pub fn legacy() -> Self {
52 Self {
53 use_xref_streams: false,
54 use_object_streams: false,
55 pdf_version: "1.4".to_string(),
56 compress_streams: true,
57 incremental_update: false,
58 }
59 }
60
61 pub fn incremental() -> Self {
63 Self {
64 use_xref_streams: false,
65 use_object_streams: false,
66 pdf_version: "1.4".to_string(),
67 compress_streams: true,
68 incremental_update: true,
69 }
70 }
71}
72
73pub struct PdfWriter<W: Write> {
74 writer: W,
75 xref_positions: HashMap<ObjectId, u64>,
76 current_position: u64,
77 next_object_id: u32,
78 catalog_id: Option<ObjectId>,
80 pages_id: Option<ObjectId>,
81 info_id: Option<ObjectId>,
82 #[allow(dead_code)]
84 field_widget_map: HashMap<String, Vec<ObjectId>>, #[allow(dead_code)]
86 field_id_map: HashMap<String, ObjectId>, form_field_ids: Vec<ObjectId>, page_ids: Vec<ObjectId>, config: WriterConfig,
91 document_used_chars: Option<std::collections::HashSet<char>>,
93 buffered_objects: HashMap<ObjectId, Vec<u8>>,
95 compressed_object_map: HashMap<ObjectId, (ObjectId, u32)>, prev_xref_offset: Option<u64>,
98 base_pdf_size: Option<u64>,
99 encrypt_obj_id: Option<ObjectId>,
101 file_id: Option<Vec<u8>>,
102 encryption_state: Option<WriterEncryptionState>,
103 pending_encrypt_dict: Option<Dictionary>,
104}
105
106struct WriterEncryptionState {
108 encryptor: crate::encryption::ObjectEncryptor,
109}
110
111impl<W: Write> PdfWriter<W> {
112 pub fn new_with_writer(writer: W) -> Self {
113 Self::with_config(writer, WriterConfig::default())
114 }
115
116 pub fn with_config(writer: W, config: WriterConfig) -> Self {
117 Self {
118 writer,
119 xref_positions: HashMap::new(),
120 current_position: 0,
121 next_object_id: 1, catalog_id: None,
123 pages_id: None,
124 info_id: None,
125 field_widget_map: HashMap::new(),
126 field_id_map: HashMap::new(),
127 form_field_ids: Vec::new(),
128 page_ids: Vec::new(),
129 config,
130 document_used_chars: None,
131 buffered_objects: HashMap::new(),
132 compressed_object_map: HashMap::new(),
133 prev_xref_offset: None,
134 base_pdf_size: None,
135 encrypt_obj_id: None,
136 file_id: None,
137 encryption_state: None,
138 pending_encrypt_dict: None,
139 }
140 }
141
142 pub fn write_document(&mut self, document: &mut Document) -> Result<()> {
143 if !document.used_characters.is_empty() {
145 self.document_used_chars = Some(document.used_characters.clone());
146 }
147
148 self.write_header()?;
149
150 self.catalog_id = Some(self.allocate_object_id());
152 self.pages_id = Some(self.allocate_object_id());
153 self.info_id = Some(self.allocate_object_id());
154
155 if let Some(ref encryption) = document.encryption {
158 self.init_encryption(encryption)?;
159 }
160
161 let font_refs = self.write_fonts(document)?;
163
164 self.write_pages(document, &font_refs)?;
166
167 self.write_form_fields(document)?;
169
170 self.write_catalog(document)?;
172
173 self.write_info(document)?;
175
176 self.write_encryption_dict()?;
178
179 if self.config.use_object_streams {
181 self.flush_object_streams()?;
182 }
183
184 let xref_position = self.current_position;
186 if self.config.use_xref_streams {
187 self.write_xref_stream()?;
188 } else {
189 self.write_xref()?;
190 }
191
192 if !self.config.use_xref_streams {
194 self.write_trailer(xref_position)?;
195 }
196
197 if let Ok(()) = self.writer.flush() {
198 }
200 Ok(())
201 }
202
203 pub fn write_incremental_update(
237 &mut self,
238 base_pdf_path: impl AsRef<std::path::Path>,
239 document: &mut Document,
240 ) -> Result<()> {
241 use std::io::{BufReader, Read, Seek, SeekFrom};
242
243 let base_pdf_file = std::fs::File::open(base_pdf_path.as_ref())?;
245 let mut pdf_reader = crate::parser::PdfReader::new(BufReader::new(base_pdf_file))?;
246
247 let base_catalog = pdf_reader.catalog()?;
249
250 let (base_pages_id, base_pages_gen) = base_catalog
252 .get("Pages")
253 .and_then(|obj| {
254 if let crate::parser::objects::PdfObject::Reference(id, gen) = obj {
255 Some((*id, *gen))
256 } else {
257 None
258 }
259 })
260 .ok_or_else(|| {
261 crate::error::PdfError::InvalidStructure(
262 "Base PDF catalog missing /Pages reference".to_string(),
263 )
264 })?;
265
266 let base_pages_obj = pdf_reader.get_object(base_pages_id, base_pages_gen)?;
268 let base_pages_kids = if let crate::parser::objects::PdfObject::Dictionary(dict) =
269 base_pages_obj
270 {
271 dict.get("Kids")
272 .and_then(|obj| {
273 if let crate::parser::objects::PdfObject::Array(arr) = obj {
274 Some(
277 arr.0
278 .iter()
279 .filter_map(|item| {
280 if let crate::parser::objects::PdfObject::Reference(id, gen) =
281 item
282 {
283 Some(crate::objects::Object::Reference(
284 crate::objects::ObjectId::new(*id, *gen),
285 ))
286 } else {
287 None
288 }
289 })
290 .collect::<Vec<_>>(),
291 )
292 } else {
293 None
294 }
295 })
296 .unwrap_or_default()
297 } else {
298 Vec::new()
299 };
300
301 let base_page_count = base_pages_kids.len();
303
304 let base_pdf = std::fs::File::open(base_pdf_path.as_ref())?;
306 let mut base_reader = BufReader::new(base_pdf);
307
308 base_reader.seek(SeekFrom::End(-100))?;
310 let mut end_buffer = vec![0u8; 100];
311 let bytes_read = base_reader.read(&mut end_buffer)?;
312 end_buffer.truncate(bytes_read);
313
314 let end_str = String::from_utf8_lossy(&end_buffer);
315 let prev_xref = if let Some(startxref_pos) = end_str.find("startxref") {
316 let after_startxref = &end_str[startxref_pos + 9..];
317
318 let number_str: String = after_startxref
319 .chars()
320 .skip_while(|c| c.is_whitespace())
321 .take_while(|c| c.is_ascii_digit())
322 .collect();
323
324 number_str.parse::<u64>().map_err(|_| {
325 crate::error::PdfError::InvalidStructure(
326 "Could not parse startxref offset".to_string(),
327 )
328 })?
329 } else {
330 return Err(crate::error::PdfError::InvalidStructure(
331 "startxref not found in base PDF".to_string(),
332 ));
333 };
334
335 base_reader.seek(SeekFrom::Start(0))?;
337 let base_size = std::io::copy(&mut base_reader, &mut self.writer)? as u64;
338
339 self.prev_xref_offset = Some(prev_xref);
341 self.base_pdf_size = Some(base_size);
342 self.current_position = base_size;
343
344 if !document.used_characters.is_empty() {
346 self.document_used_chars = Some(document.used_characters.clone());
347 }
348
349 self.catalog_id = Some(self.allocate_object_id());
351 self.pages_id = Some(self.allocate_object_id());
352 self.info_id = Some(self.allocate_object_id());
353
354 let font_refs = self.write_fonts(document)?;
356
357 self.write_pages(document, &font_refs)?;
359
360 self.write_form_fields(document)?;
362
363 let catalog_id = self.get_catalog_id()?;
365 let new_pages_id = self.get_pages_id()?;
366
367 let mut catalog = crate::objects::Dictionary::new();
368 catalog.set("Type", crate::objects::Object::Name("Catalog".to_string()));
369 catalog.set("Pages", crate::objects::Object::Reference(new_pages_id));
370
371 self.write_object(catalog_id, crate::objects::Object::Dictionary(catalog))?;
376
377 let mut all_pages_kids = base_pages_kids;
379
380 for page_id in &self.page_ids {
382 all_pages_kids.push(crate::objects::Object::Reference(*page_id));
383 }
384
385 let mut pages_dict = crate::objects::Dictionary::new();
386 pages_dict.set("Type", crate::objects::Object::Name("Pages".to_string()));
387 pages_dict.set("Kids", crate::objects::Object::Array(all_pages_kids));
388 pages_dict.set(
389 "Count",
390 crate::objects::Object::Integer((base_page_count + self.page_ids.len()) as i64),
391 );
392
393 self.write_object(new_pages_id, crate::objects::Object::Dictionary(pages_dict))?;
394
395 self.write_info(document)?;
397
398 let xref_position = self.current_position;
400 self.write_xref()?;
401
402 self.write_trailer(xref_position)?;
404
405 self.writer.flush()?;
406 Ok(())
407 }
408
409 pub fn write_incremental_with_page_replacement(
475 &mut self,
476 base_pdf_path: impl AsRef<std::path::Path>,
477 document: &mut Document,
478 ) -> Result<()> {
479 use std::io::Cursor;
480
481 let base_pdf_bytes = std::fs::read(base_pdf_path.as_ref())?;
483 let base_size = base_pdf_bytes.len() as u64;
484
485 let mut pdf_reader = crate::parser::PdfReader::new(Cursor::new(&base_pdf_bytes))?;
487
488 let base_catalog = pdf_reader.catalog()?;
489
490 let (base_pages_id, base_pages_gen) = base_catalog
491 .get("Pages")
492 .and_then(|obj| {
493 if let crate::parser::objects::PdfObject::Reference(id, gen) = obj {
494 Some((*id, *gen))
495 } else {
496 None
497 }
498 })
499 .ok_or_else(|| {
500 crate::error::PdfError::InvalidStructure(
501 "Base PDF catalog missing /Pages reference".to_string(),
502 )
503 })?;
504
505 let base_pages_obj = pdf_reader.get_object(base_pages_id, base_pages_gen)?;
506 let base_pages_kids = if let crate::parser::objects::PdfObject::Dictionary(dict) =
507 base_pages_obj
508 {
509 dict.get("Kids")
510 .and_then(|obj| {
511 if let crate::parser::objects::PdfObject::Array(arr) = obj {
512 Some(
513 arr.0
514 .iter()
515 .filter_map(|item| {
516 if let crate::parser::objects::PdfObject::Reference(id, gen) =
517 item
518 {
519 Some(crate::objects::Object::Reference(
520 crate::objects::ObjectId::new(*id, *gen),
521 ))
522 } else {
523 None
524 }
525 })
526 .collect::<Vec<_>>(),
527 )
528 } else {
529 None
530 }
531 })
532 .unwrap_or_default()
533 } else {
534 Vec::new()
535 };
536
537 let base_page_count = base_pages_kids.len();
538
539 let start_search = if base_size > 100 { base_size - 100 } else { 0 } as usize;
541 let end_bytes = &base_pdf_bytes[start_search..];
542 let end_str = String::from_utf8_lossy(end_bytes);
543
544 let prev_xref = if let Some(startxref_pos) = end_str.find("startxref") {
545 let after_startxref = &end_str[startxref_pos + 9..];
546 let number_str: String = after_startxref
547 .chars()
548 .skip_while(|c| c.is_whitespace())
549 .take_while(|c| c.is_ascii_digit())
550 .collect();
551
552 number_str.parse::<u64>().map_err(|_| {
553 crate::error::PdfError::InvalidStructure(
554 "Could not parse startxref offset".to_string(),
555 )
556 })?
557 } else {
558 return Err(crate::error::PdfError::InvalidStructure(
559 "startxref not found in base PDF".to_string(),
560 ));
561 };
562
563 self.writer.write_all(&base_pdf_bytes)?;
565
566 self.prev_xref_offset = Some(prev_xref);
567 self.base_pdf_size = Some(base_size);
568 self.current_position = base_size;
569
570 if !document.used_characters.is_empty() {
572 self.document_used_chars = Some(document.used_characters.clone());
573 }
574
575 self.catalog_id = Some(self.allocate_object_id());
576 self.pages_id = Some(self.allocate_object_id());
577 self.info_id = Some(self.allocate_object_id());
578
579 let font_refs = self.write_fonts(document)?;
580 self.write_pages(document, &font_refs)?;
581 self.write_form_fields(document)?;
582
583 let catalog_id = self.get_catalog_id()?;
585 let new_pages_id = self.get_pages_id()?;
586
587 let mut catalog = crate::objects::Dictionary::new();
588 catalog.set("Type", crate::objects::Object::Name("Catalog".to_string()));
589 catalog.set("Pages", crate::objects::Object::Reference(new_pages_id));
590 self.write_object(catalog_id, crate::objects::Object::Dictionary(catalog))?;
591
592 let mut all_pages_kids = Vec::new();
594 let replacement_count = document.pages.len();
595
596 for page_id in &self.page_ids {
598 all_pages_kids.push(crate::objects::Object::Reference(*page_id));
599 }
600
601 if replacement_count < base_page_count {
603 for i in replacement_count..base_page_count {
604 if let Some(page_ref) = base_pages_kids.get(i) {
605 all_pages_kids.push(page_ref.clone());
606 }
607 }
608 }
609
610 let mut pages_dict = crate::objects::Dictionary::new();
611 pages_dict.set("Type", crate::objects::Object::Name("Pages".to_string()));
612 pages_dict.set(
613 "Kids",
614 crate::objects::Object::Array(all_pages_kids.clone()),
615 );
616 pages_dict.set(
617 "Count",
618 crate::objects::Object::Integer(all_pages_kids.len() as i64),
619 );
620
621 self.write_object(new_pages_id, crate::objects::Object::Dictionary(pages_dict))?;
622 self.write_info(document)?;
623
624 let xref_position = self.current_position;
625 self.write_xref()?;
626 self.write_trailer(xref_position)?;
627
628 self.writer.flush()?;
629 Ok(())
630 }
631
632 pub fn write_incremental_with_overlay<P: AsRef<std::path::Path>>(
680 &mut self,
681 base_pdf_path: P,
682 mut overlay_fn: impl FnMut(&mut crate::Page) -> Result<()>,
683 ) -> Result<()> {
684 use std::io::Cursor;
685
686 let base_pdf_bytes = std::fs::read(base_pdf_path.as_ref())?;
688 let base_size = base_pdf_bytes.len() as u64;
689
690 let pdf_reader = crate::parser::PdfReader::new(Cursor::new(&base_pdf_bytes))?;
692 let parsed_doc = crate::parser::PdfDocument::new(pdf_reader);
693
694 let page_count = parsed_doc.page_count()?;
696
697 let start_search = if base_size > 100 { base_size - 100 } else { 0 } as usize;
699 let end_bytes = &base_pdf_bytes[start_search..];
700 let end_str = String::from_utf8_lossy(end_bytes);
701
702 let prev_xref = if let Some(startxref_pos) = end_str.find("startxref") {
703 let after_startxref = &end_str[startxref_pos + 9..];
704 let number_str: String = after_startxref
705 .chars()
706 .skip_while(|c| c.is_whitespace())
707 .take_while(|c| c.is_ascii_digit())
708 .collect();
709
710 number_str.parse::<u64>().map_err(|_| {
711 crate::error::PdfError::InvalidStructure(
712 "Could not parse startxref offset".to_string(),
713 )
714 })?
715 } else {
716 return Err(crate::error::PdfError::InvalidStructure(
717 "startxref not found in base PDF".to_string(),
718 ));
719 };
720
721 self.writer.write_all(&base_pdf_bytes)?;
723
724 self.prev_xref_offset = Some(prev_xref);
725 self.base_pdf_size = Some(base_size);
726 self.current_position = base_size;
727
728 let mut temp_doc = crate::Document::new();
730
731 for page_idx in 0..page_count {
732 let parsed_page = parsed_doc.get_page(page_idx)?;
734 let mut writable_page =
735 crate::Page::from_parsed_with_content(&parsed_page, &parsed_doc)?;
736
737 overlay_fn(&mut writable_page)?;
739
740 temp_doc.add_page(writable_page);
742 }
743
744 if !temp_doc.used_characters.is_empty() {
747 self.document_used_chars = Some(temp_doc.used_characters.clone());
748 }
749
750 self.catalog_id = Some(self.allocate_object_id());
751 self.pages_id = Some(self.allocate_object_id());
752 self.info_id = Some(self.allocate_object_id());
753
754 let font_refs = self.write_fonts(&temp_doc)?;
755 self.write_pages(&temp_doc, &font_refs)?;
756 self.write_form_fields(&mut temp_doc)?;
757
758 let catalog_id = self.get_catalog_id()?;
760 let new_pages_id = self.get_pages_id()?;
761
762 let mut catalog = crate::objects::Dictionary::new();
763 catalog.set("Type", crate::objects::Object::Name("Catalog".to_string()));
764 catalog.set("Pages", crate::objects::Object::Reference(new_pages_id));
765 self.write_object(catalog_id, crate::objects::Object::Dictionary(catalog))?;
766
767 let mut all_pages_kids = Vec::new();
769 for page_id in &self.page_ids {
770 all_pages_kids.push(crate::objects::Object::Reference(*page_id));
771 }
772
773 let mut pages_dict = crate::objects::Dictionary::new();
774 pages_dict.set("Type", crate::objects::Object::Name("Pages".to_string()));
775 pages_dict.set(
776 "Kids",
777 crate::objects::Object::Array(all_pages_kids.clone()),
778 );
779 pages_dict.set(
780 "Count",
781 crate::objects::Object::Integer(all_pages_kids.len() as i64),
782 );
783
784 self.write_object(new_pages_id, crate::objects::Object::Dictionary(pages_dict))?;
785 self.write_info(&temp_doc)?;
786
787 let xref_position = self.current_position;
788 self.write_xref()?;
789 self.write_trailer(xref_position)?;
790
791 self.writer.flush()?;
792 Ok(())
793 }
794
795 fn write_header(&mut self) -> Result<()> {
796 let header = format!("%PDF-{}\n", self.config.pdf_version);
797 self.write_bytes(header.as_bytes())?;
798 self.write_bytes(&[b'%', 0xE2, 0xE3, 0xCF, 0xD3, b'\n'])?;
800 Ok(())
801 }
802
803 fn convert_pdf_objects_dict_to_writer(
806 &self,
807 pdf_dict: &crate::pdf_objects::Dictionary,
808 ) -> crate::objects::Dictionary {
809 let mut writer_dict = crate::objects::Dictionary::new();
810
811 for (key, value) in pdf_dict.iter() {
812 let writer_obj = self.convert_pdf_object_to_writer(value);
813 writer_dict.set(key.as_str(), writer_obj);
814 }
815
816 writer_dict
817 }
818
819 fn convert_pdf_object_to_writer(
820 &self,
821 obj: &crate::pdf_objects::Object,
822 ) -> crate::objects::Object {
823 use crate::objects::Object as WriterObj;
824 use crate::pdf_objects::Object as PdfObj;
825
826 match obj {
827 PdfObj::Null => WriterObj::Null,
828 PdfObj::Boolean(b) => WriterObj::Boolean(*b),
829 PdfObj::Integer(i) => WriterObj::Integer(*i),
830 PdfObj::Real(f) => WriterObj::Real(*f),
831 PdfObj::String(s) => {
832 WriterObj::String(String::from_utf8_lossy(s.as_bytes()).to_string())
833 }
834 PdfObj::Name(n) => WriterObj::Name(n.as_str().to_string()),
835 PdfObj::Array(arr) => {
836 let items: Vec<WriterObj> = arr
837 .iter()
838 .map(|item| self.convert_pdf_object_to_writer(item))
839 .collect();
840 WriterObj::Array(items)
841 }
842 PdfObj::Dictionary(dict) => {
843 WriterObj::Dictionary(self.convert_pdf_objects_dict_to_writer(dict))
844 }
845 PdfObj::Stream(stream) => {
846 let dict = self.convert_pdf_objects_dict_to_writer(&stream.dict);
847 WriterObj::Stream(dict, stream.data.clone())
848 }
849 PdfObj::Reference(id) => {
850 WriterObj::Reference(crate::objects::ObjectId::new(id.number(), id.generation()))
851 }
852 }
853 }
854
855 fn write_catalog(&mut self, document: &mut Document) -> Result<()> {
856 let catalog_id = self.get_catalog_id()?;
857 let pages_id = self.get_pages_id()?;
858
859 let mut catalog = Dictionary::new();
860 catalog.set("Type", Object::Name("Catalog".to_string()));
861 catalog.set("Pages", Object::Reference(pages_id));
862
863 if let Some(_form_manager) = &document.form_manager {
866 if document.acro_form.is_none() {
868 document.acro_form = Some(crate::forms::AcroForm::new());
869 }
870 }
871
872 if let Some(acro_form) = &document.acro_form {
874 let acro_form_id = self.allocate_object_id();
876
877 self.write_object(acro_form_id, Object::Dictionary(acro_form.to_dict()))?;
879
880 catalog.set("AcroForm", Object::Reference(acro_form_id));
882 }
883
884 if let Some(outline_tree) = &document.outline {
886 if !outline_tree.items.is_empty() {
887 let outline_root_id = self.write_outline_tree(outline_tree)?;
888 catalog.set("Outlines", Object::Reference(outline_root_id));
889 }
890 }
891
892 if let Some(struct_tree) = &document.struct_tree {
894 if !struct_tree.is_empty() {
895 let struct_tree_root_id = self.write_struct_tree(struct_tree)?;
896 catalog.set("StructTreeRoot", Object::Reference(struct_tree_root_id));
897 catalog.set("MarkInfo", {
899 let mut mark_info = Dictionary::new();
900 mark_info.set("Marked", Object::Boolean(true));
901 Object::Dictionary(mark_info)
902 });
903 }
904 }
905
906 let xmp_metadata = document.create_xmp_metadata();
909 let xmp_packet = xmp_metadata.to_xmp_packet();
910 let metadata_id = self.allocate_object_id();
911
912 let mut metadata_dict = Dictionary::new();
914 metadata_dict.set("Type", Object::Name("Metadata".to_string()));
915 metadata_dict.set("Subtype", Object::Name("XML".to_string()));
916 metadata_dict.set("Length", Object::Integer(xmp_packet.len() as i64));
917
918 self.write_object(
920 metadata_id,
921 Object::Stream(metadata_dict, xmp_packet.into_bytes()),
922 )?;
923
924 catalog.set("Metadata", Object::Reference(metadata_id));
926
927 self.write_object(catalog_id, Object::Dictionary(catalog))?;
928 Ok(())
929 }
930
931 fn write_page_content(&mut self, content_id: ObjectId, page: &crate::page::Page) -> Result<()> {
932 let mut page_copy = page.clone();
933 let content = page_copy.generate_content()?;
934
935 #[cfg(feature = "compression")]
937 {
938 use crate::objects::Stream;
939 let mut stream = Stream::new(content);
940 if self.config.compress_streams {
942 stream.compress_flate()?;
943 }
944
945 self.write_object(
946 content_id,
947 Object::Stream(stream.dictionary().clone(), stream.data().to_vec()),
948 )?;
949 }
950
951 #[cfg(not(feature = "compression"))]
952 {
953 let mut stream_dict = Dictionary::new();
954 stream_dict.set("Length", Object::Integer(content.len() as i64));
955
956 self.write_object(content_id, Object::Stream(stream_dict, content))?;
957 }
958
959 Ok(())
960 }
961
962 fn write_outline_tree(
963 &mut self,
964 outline_tree: &crate::structure::OutlineTree,
965 ) -> Result<ObjectId> {
966 let outline_root_id = self.allocate_object_id();
968
969 let mut outline_root = Dictionary::new();
970 outline_root.set("Type", Object::Name("Outlines".to_string()));
971
972 if !outline_tree.items.is_empty() {
973 let mut item_ids = Vec::new();
975
976 fn count_items(items: &[crate::structure::OutlineItem]) -> usize {
978 let mut count = items.len();
979 for item in items {
980 count += count_items(&item.children);
981 }
982 count
983 }
984
985 let total_items = count_items(&outline_tree.items);
986
987 for _ in 0..total_items {
989 item_ids.push(self.allocate_object_id());
990 }
991
992 let mut id_index = 0;
993
994 let first_id = item_ids[0];
996 let last_id = item_ids[outline_tree.items.len() - 1];
997
998 outline_root.set("First", Object::Reference(first_id));
999 outline_root.set("Last", Object::Reference(last_id));
1000
1001 let visible_count = outline_tree.visible_count();
1003 outline_root.set("Count", Object::Integer(visible_count));
1004
1005 let mut written_items = Vec::new();
1007
1008 for (i, item) in outline_tree.items.iter().enumerate() {
1009 let item_id = item_ids[id_index];
1010 id_index += 1;
1011
1012 let prev_id = if i > 0 { Some(item_ids[i - 1]) } else { None };
1013 let next_id = if i < outline_tree.items.len() - 1 {
1014 Some(item_ids[i + 1])
1015 } else {
1016 None
1017 };
1018
1019 let children_ids = self.write_outline_item(
1021 item,
1022 item_id,
1023 outline_root_id,
1024 prev_id,
1025 next_id,
1026 &mut item_ids,
1027 &mut id_index,
1028 )?;
1029
1030 written_items.extend(children_ids);
1031 }
1032 }
1033
1034 self.write_object(outline_root_id, Object::Dictionary(outline_root))?;
1035 Ok(outline_root_id)
1036 }
1037
1038 #[allow(clippy::too_many_arguments)]
1039 fn write_outline_item(
1040 &mut self,
1041 item: &crate::structure::OutlineItem,
1042 item_id: ObjectId,
1043 parent_id: ObjectId,
1044 prev_id: Option<ObjectId>,
1045 next_id: Option<ObjectId>,
1046 all_ids: &mut Vec<ObjectId>,
1047 id_index: &mut usize,
1048 ) -> Result<Vec<ObjectId>> {
1049 let mut written_ids = vec![item_id];
1050
1051 let (first_child_id, last_child_id) = if !item.children.is_empty() {
1053 let first_idx = *id_index;
1054 let first_id = all_ids[first_idx];
1055 let last_idx = first_idx + item.children.len() - 1;
1056 let last_id = all_ids[last_idx];
1057
1058 for (i, child) in item.children.iter().enumerate() {
1060 let child_id = all_ids[*id_index];
1061 *id_index += 1;
1062
1063 let child_prev = if i > 0 {
1064 Some(all_ids[first_idx + i - 1])
1065 } else {
1066 None
1067 };
1068 let child_next = if i < item.children.len() - 1 {
1069 Some(all_ids[first_idx + i + 1])
1070 } else {
1071 None
1072 };
1073
1074 let child_ids = self.write_outline_item(
1075 child, child_id, item_id, child_prev, child_next, all_ids, id_index,
1077 )?;
1078
1079 written_ids.extend(child_ids);
1080 }
1081
1082 (Some(first_id), Some(last_id))
1083 } else {
1084 (None, None)
1085 };
1086
1087 let item_dict = crate::structure::outline_item_to_dict(
1089 item,
1090 parent_id,
1091 first_child_id,
1092 last_child_id,
1093 prev_id,
1094 next_id,
1095 );
1096
1097 self.write_object(item_id, Object::Dictionary(item_dict))?;
1098
1099 Ok(written_ids)
1100 }
1101
1102 fn write_struct_tree(
1104 &mut self,
1105 struct_tree: &crate::structure::StructTree,
1106 ) -> Result<ObjectId> {
1107 let struct_tree_root_id = self.allocate_object_id();
1109 let mut element_ids = Vec::new();
1110 for _ in 0..struct_tree.len() {
1111 element_ids.push(self.allocate_object_id());
1112 }
1113
1114 let mut parent_map: std::collections::HashMap<usize, ObjectId> =
1116 std::collections::HashMap::new();
1117
1118 if let Some(root_index) = struct_tree.root_index() {
1120 parent_map.insert(root_index, struct_tree_root_id);
1121
1122 fn map_children_parents(
1124 tree: &crate::structure::StructTree,
1125 parent_index: usize,
1126 parent_id: ObjectId,
1127 element_ids: &[ObjectId],
1128 parent_map: &mut std::collections::HashMap<usize, ObjectId>,
1129 ) {
1130 if let Some(parent_elem) = tree.get(parent_index) {
1131 for &child_index in &parent_elem.children {
1132 parent_map.insert(child_index, parent_id);
1133 map_children_parents(
1134 tree,
1135 child_index,
1136 element_ids[child_index],
1137 element_ids,
1138 parent_map,
1139 );
1140 }
1141 }
1142 }
1143
1144 map_children_parents(
1145 struct_tree,
1146 root_index,
1147 element_ids[root_index],
1148 &element_ids,
1149 &mut parent_map,
1150 );
1151 }
1152
1153 for (index, element) in struct_tree.iter().enumerate() {
1155 let element_id = element_ids[index];
1156 let mut element_dict = Dictionary::new();
1157
1158 element_dict.set("Type", Object::Name("StructElem".to_string()));
1159 element_dict.set("S", Object::Name(element.structure_type.as_pdf_name()));
1160
1161 if let Some(&parent_id) = parent_map.get(&index) {
1163 element_dict.set("P", Object::Reference(parent_id));
1164 }
1165
1166 if let Some(ref id) = element.id {
1168 element_dict.set("ID", Object::String(id.clone()));
1169 }
1170
1171 if let Some(ref lang) = element.attributes.lang {
1173 element_dict.set("Lang", Object::String(lang.clone()));
1174 }
1175 if let Some(ref alt) = element.attributes.alt {
1176 element_dict.set("Alt", Object::String(alt.clone()));
1177 }
1178 if let Some(ref actual_text) = element.attributes.actual_text {
1179 element_dict.set("ActualText", Object::String(actual_text.clone()));
1180 }
1181 if let Some(ref title) = element.attributes.title {
1182 element_dict.set("T", Object::String(title.clone()));
1183 }
1184 if let Some(bbox) = element.attributes.bbox {
1185 element_dict.set(
1186 "BBox",
1187 Object::Array(vec![
1188 Object::Real(bbox[0]),
1189 Object::Real(bbox[1]),
1190 Object::Real(bbox[2]),
1191 Object::Real(bbox[3]),
1192 ]),
1193 );
1194 }
1195
1196 let mut kids = Vec::new();
1198
1199 for &child_index in &element.children {
1201 kids.push(Object::Reference(element_ids[child_index]));
1202 }
1203
1204 for mcid_ref in &element.mcids {
1206 let mut mcr = Dictionary::new();
1207 mcr.set("Type", Object::Name("MCR".to_string()));
1208 mcr.set("Pg", Object::Integer(mcid_ref.page_index as i64));
1209 mcr.set("MCID", Object::Integer(mcid_ref.mcid as i64));
1210 kids.push(Object::Dictionary(mcr));
1211 }
1212
1213 if !kids.is_empty() {
1214 element_dict.set("K", Object::Array(kids));
1215 }
1216
1217 self.write_object(element_id, Object::Dictionary(element_dict))?;
1218 }
1219
1220 let mut struct_tree_root = Dictionary::new();
1222 struct_tree_root.set("Type", Object::Name("StructTreeRoot".to_string()));
1223
1224 if let Some(root_index) = struct_tree.root_index() {
1226 struct_tree_root.set("K", Object::Reference(element_ids[root_index]));
1227 }
1228
1229 if !struct_tree.role_map.mappings().is_empty() {
1231 let mut role_map = Dictionary::new();
1232 for (custom_type, standard_type) in struct_tree.role_map.mappings() {
1233 role_map.set(
1234 custom_type.as_str(),
1235 Object::Name(standard_type.as_pdf_name().to_string()),
1236 );
1237 }
1238 struct_tree_root.set("RoleMap", Object::Dictionary(role_map));
1239 }
1240
1241 self.write_object(struct_tree_root_id, Object::Dictionary(struct_tree_root))?;
1242 Ok(struct_tree_root_id)
1243 }
1244
1245 fn write_form_fields(&mut self, document: &mut Document) -> Result<()> {
1246 if !self.form_field_ids.is_empty() {
1248 if let Some(acro_form) = &mut document.acro_form {
1249 acro_form.fields.clear();
1251 for field_id in &self.form_field_ids {
1252 acro_form.add_field(*field_id);
1253 }
1254
1255 acro_form.need_appearances = true;
1257 if acro_form.da.is_none() {
1258 acro_form.da = Some("/Helv 12 Tf 0 g".to_string());
1259 }
1260 }
1261 }
1262 Ok(())
1263 }
1264
1265 fn write_info(&mut self, document: &Document) -> Result<()> {
1266 let info_id = self.get_info_id()?;
1267 let mut info_dict = Dictionary::new();
1268
1269 if let Some(ref title) = document.metadata.title {
1270 info_dict.set("Title", Object::String(title.clone()));
1271 }
1272 if let Some(ref author) = document.metadata.author {
1273 info_dict.set("Author", Object::String(author.clone()));
1274 }
1275 if let Some(ref subject) = document.metadata.subject {
1276 info_dict.set("Subject", Object::String(subject.clone()));
1277 }
1278 if let Some(ref keywords) = document.metadata.keywords {
1279 info_dict.set("Keywords", Object::String(keywords.clone()));
1280 }
1281 if let Some(ref creator) = document.metadata.creator {
1282 info_dict.set("Creator", Object::String(creator.clone()));
1283 }
1284 if let Some(ref producer) = document.metadata.producer {
1285 info_dict.set("Producer", Object::String(producer.clone()));
1286 }
1287
1288 if let Some(creation_date) = document.metadata.creation_date {
1290 let date_string = format_pdf_date(creation_date);
1291 info_dict.set("CreationDate", Object::String(date_string));
1292 }
1293
1294 if let Some(mod_date) = document.metadata.modification_date {
1296 let date_string = format_pdf_date(mod_date);
1297 info_dict.set("ModDate", Object::String(date_string));
1298 }
1299
1300 let edition = super::Edition::OpenSource;
1303
1304 let signature = super::PdfSignature::new(document, edition);
1305 signature.write_to_info_dict(&mut info_dict);
1306
1307 self.write_object(info_id, Object::Dictionary(info_dict))?;
1308 Ok(())
1309 }
1310
1311 fn write_fonts(&mut self, document: &Document) -> Result<HashMap<String, ObjectId>> {
1312 let mut font_refs = HashMap::new();
1313
1314 for font_name in document.custom_font_names() {
1316 if let Some(font) = document.get_custom_font(&font_name) {
1317 let font_id = self.write_font_with_unicode_support(&font_name, &font)?;
1320 font_refs.insert(font_name.clone(), font_id);
1321 }
1322 }
1323
1324 Ok(font_refs)
1325 }
1326
1327 fn write_font_with_unicode_support(
1329 &mut self,
1330 font_name: &str,
1331 font: &crate::fonts::Font,
1332 ) -> Result<ObjectId> {
1333 self.write_type0_font_from_font(font_name, font)
1336 }
1337
1338 fn write_type0_font_from_font(
1340 &mut self,
1341 font_name: &str,
1342 font: &crate::fonts::Font,
1343 ) -> Result<ObjectId> {
1344 let used_chars = self.document_used_chars.clone().unwrap_or_else(|| {
1346 let mut chars = std::collections::HashSet::new();
1348 for ch in "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,!?".chars()
1349 {
1350 chars.insert(ch);
1351 }
1352 chars
1353 });
1354 let font_id = self.allocate_object_id();
1356 let descendant_font_id = self.allocate_object_id();
1357 let descriptor_id = self.allocate_object_id();
1358 let font_file_id = self.allocate_object_id();
1359 let to_unicode_id = self.allocate_object_id();
1360
1361 let (font_data_to_embed, subset_glyph_mapping, original_font_for_widths) =
1365 if font.data.len() > 100_000 && !used_chars.is_empty() {
1366 match crate::text::fonts::truetype_subsetter::subset_font(
1368 font.data.clone(),
1369 &used_chars,
1370 ) {
1371 Ok(subset_result) => {
1372 (
1375 subset_result.font_data,
1376 Some(subset_result.glyph_mapping),
1377 font.clone(),
1378 )
1379 }
1380 Err(_) => {
1381 if font.data.len() < 25_000_000 {
1383 (font.data.clone(), None, font.clone())
1384 } else {
1385 (Vec::new(), None, font.clone())
1387 }
1388 }
1389 }
1390 } else {
1391 (font.data.clone(), None, font.clone())
1393 };
1394
1395 if !font_data_to_embed.is_empty() {
1396 let mut font_file_dict = Dictionary::new();
1397 match font.format {
1399 crate::fonts::FontFormat::OpenType => {
1400 font_file_dict.set("Subtype", Object::Name("OpenType".to_string()));
1402 font_file_dict.set("Length1", Object::Integer(font_data_to_embed.len() as i64));
1403 }
1404 crate::fonts::FontFormat::TrueType => {
1405 font_file_dict.set("Length1", Object::Integer(font_data_to_embed.len() as i64));
1407 }
1408 }
1409 let font_stream_obj = Object::Stream(font_file_dict, font_data_to_embed);
1410 self.write_object(font_file_id, font_stream_obj)?;
1411 } else {
1412 let font_file_dict = Dictionary::new();
1414 let font_stream_obj = Object::Stream(font_file_dict, Vec::new());
1415 self.write_object(font_file_id, font_stream_obj)?;
1416 }
1417
1418 let mut descriptor = Dictionary::new();
1420 descriptor.set("Type", Object::Name("FontDescriptor".to_string()));
1421 descriptor.set("FontName", Object::Name(font_name.to_string()));
1422 descriptor.set("Flags", Object::Integer(4)); descriptor.set(
1424 "FontBBox",
1425 Object::Array(vec![
1426 Object::Integer(font.descriptor.font_bbox[0] as i64),
1427 Object::Integer(font.descriptor.font_bbox[1] as i64),
1428 Object::Integer(font.descriptor.font_bbox[2] as i64),
1429 Object::Integer(font.descriptor.font_bbox[3] as i64),
1430 ]),
1431 );
1432 descriptor.set(
1433 "ItalicAngle",
1434 Object::Real(font.descriptor.italic_angle as f64),
1435 );
1436 descriptor.set("Ascent", Object::Real(font.descriptor.ascent as f64));
1437 descriptor.set("Descent", Object::Real(font.descriptor.descent as f64));
1438 descriptor.set("CapHeight", Object::Real(font.descriptor.cap_height as f64));
1439 descriptor.set("StemV", Object::Real(font.descriptor.stem_v as f64));
1440 let font_file_key = match font.format {
1442 crate::fonts::FontFormat::OpenType => "FontFile3", crate::fonts::FontFormat::TrueType => "FontFile2", };
1445 descriptor.set(font_file_key, Object::Reference(font_file_id));
1446 self.write_object(descriptor_id, Object::Dictionary(descriptor))?;
1447
1448 let mut cid_font = Dictionary::new();
1450 cid_font.set("Type", Object::Name("Font".to_string()));
1451 let cid_font_subtype =
1453 if CjkFontType::should_use_cidfonttype2_for_preview_compatibility(font_name) {
1454 "CIDFontType2" } else {
1456 match font.format {
1457 crate::fonts::FontFormat::OpenType => "CIDFontType0", crate::fonts::FontFormat::TrueType => "CIDFontType2", }
1460 };
1461 cid_font.set("Subtype", Object::Name(cid_font_subtype.to_string()));
1462 cid_font.set("BaseFont", Object::Name(font_name.to_string()));
1463
1464 let mut cid_system_info = Dictionary::new();
1466 let (registry, ordering, supplement) =
1467 if let Some(cjk_type) = CjkFontType::detect_from_name(font_name) {
1468 cjk_type.cid_system_info()
1469 } else {
1470 ("Adobe", "Identity", 0)
1471 };
1472
1473 cid_system_info.set("Registry", Object::String(registry.to_string()));
1474 cid_system_info.set("Ordering", Object::String(ordering.to_string()));
1475 cid_system_info.set("Supplement", Object::Integer(supplement as i64));
1476 cid_font.set("CIDSystemInfo", Object::Dictionary(cid_system_info));
1477
1478 cid_font.set("FontDescriptor", Object::Reference(descriptor_id));
1479
1480 let default_width = self.calculate_default_width(font);
1482 cid_font.set("DW", Object::Integer(default_width));
1483
1484 let w_array = self.generate_width_array(
1488 &original_font_for_widths,
1489 default_width,
1490 subset_glyph_mapping.as_ref(),
1491 );
1492 cid_font.set("W", Object::Array(w_array));
1493
1494 if cid_font_subtype == "CIDFontType2" {
1498 let cid_to_gid_map =
1500 self.generate_cid_to_gid_map(font, subset_glyph_mapping.as_ref())?;
1501 if !cid_to_gid_map.is_empty() {
1502 let cid_to_gid_map_id = self.allocate_object_id();
1504 let mut map_dict = Dictionary::new();
1505 map_dict.set("Length", Object::Integer(cid_to_gid_map.len() as i64));
1506 let map_stream = Object::Stream(map_dict, cid_to_gid_map);
1507 self.write_object(cid_to_gid_map_id, map_stream)?;
1508 cid_font.set("CIDToGIDMap", Object::Reference(cid_to_gid_map_id));
1509 } else {
1510 cid_font.set("CIDToGIDMap", Object::Name("Identity".to_string()));
1511 }
1512 }
1513 self.write_object(descendant_font_id, Object::Dictionary(cid_font))?;
1516
1517 let cmap_data = self.generate_tounicode_cmap_from_font(font);
1519 let cmap_dict = Dictionary::new();
1520 let cmap_stream = Object::Stream(cmap_dict, cmap_data);
1521 self.write_object(to_unicode_id, cmap_stream)?;
1522
1523 let mut type0_font = Dictionary::new();
1525 type0_font.set("Type", Object::Name("Font".to_string()));
1526 type0_font.set("Subtype", Object::Name("Type0".to_string()));
1527 type0_font.set("BaseFont", Object::Name(font_name.to_string()));
1528 type0_font.set("Encoding", Object::Name("Identity-H".to_string()));
1529 type0_font.set(
1530 "DescendantFonts",
1531 Object::Array(vec![Object::Reference(descendant_font_id)]),
1532 );
1533 type0_font.set("ToUnicode", Object::Reference(to_unicode_id));
1534
1535 self.write_object(font_id, Object::Dictionary(type0_font))?;
1536
1537 Ok(font_id)
1538 }
1539
1540 fn calculate_default_width(&self, font: &crate::fonts::Font) -> i64 {
1542 use crate::text::fonts::truetype::TrueTypeFont;
1543
1544 if let Ok(tt_font) = TrueTypeFont::parse(font.data.clone()) {
1546 if let Ok(cmap_tables) = tt_font.parse_cmap() {
1547 if let Some(cmap) = cmap_tables
1548 .iter()
1549 .find(|t| t.platform_id == 3 && t.encoding_id == 1)
1550 .or_else(|| cmap_tables.iter().find(|t| t.platform_id == 0))
1551 {
1552 if let Ok(widths) = tt_font.get_glyph_widths(&cmap.mappings) {
1553 let common_chars =
1557 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ";
1558 let mut total_width = 0;
1559 let mut count = 0;
1560
1561 for ch in common_chars.chars() {
1562 let unicode = ch as u32;
1563 if let Some(&pdf_width) = widths.get(&unicode) {
1564 total_width += pdf_width as i64;
1565 count += 1;
1566 }
1567 }
1568
1569 if count > 0 {
1570 return total_width / count;
1571 }
1572 }
1573 }
1574 }
1575 }
1576
1577 500
1579 }
1580
1581 fn generate_width_array(
1583 &self,
1584 font: &crate::fonts::Font,
1585 _default_width: i64,
1586 subset_mapping: Option<&HashMap<u32, u16>>,
1587 ) -> Vec<Object> {
1588 use crate::text::fonts::truetype::TrueTypeFont;
1589
1590 let mut w_array = Vec::new();
1591
1592 if let Ok(tt_font) = TrueTypeFont::parse(font.data.clone()) {
1594 let char_to_glyph = {
1598 if let Ok(cmap_tables) = tt_font.parse_cmap() {
1600 if let Some(cmap) = cmap_tables
1601 .iter()
1602 .find(|t| t.platform_id == 3 && t.encoding_id == 1)
1603 .or_else(|| cmap_tables.iter().find(|t| t.platform_id == 0))
1604 {
1605 if let Some(subset_map) = subset_mapping {
1607 let mut filtered = HashMap::new();
1608 for unicode in subset_map.keys() {
1609 if let Some(&orig_glyph) = cmap.mappings.get(unicode) {
1611 filtered.insert(*unicode, orig_glyph);
1612 }
1613 }
1614 filtered
1615 } else {
1616 cmap.mappings.clone()
1617 }
1618 } else {
1619 HashMap::new()
1620 }
1621 } else {
1622 HashMap::new()
1623 }
1624 };
1625
1626 if !char_to_glyph.is_empty() {
1627 if let Ok(widths) = tt_font.get_glyph_widths(&char_to_glyph) {
1629 let mut sorted_chars: Vec<_> = widths.iter().collect();
1634 sorted_chars.sort_by_key(|(unicode, _)| *unicode);
1635
1636 let mut i = 0;
1637 while i < sorted_chars.len() {
1638 let start_unicode = *sorted_chars[i].0;
1639 let pdf_width = *sorted_chars[i].1 as i64;
1641
1642 let mut end_unicode = start_unicode;
1644 let mut j = i + 1;
1645 while j < sorted_chars.len() && *sorted_chars[j].0 == end_unicode + 1 {
1646 let next_pdf_width = *sorted_chars[j].1 as i64;
1647 if next_pdf_width == pdf_width {
1648 end_unicode = *sorted_chars[j].0;
1649 j += 1;
1650 } else {
1651 break;
1652 }
1653 }
1654
1655 if start_unicode == end_unicode {
1657 w_array.push(Object::Integer(start_unicode as i64));
1659 w_array.push(Object::Array(vec![Object::Integer(pdf_width)]));
1660 } else {
1661 w_array.push(Object::Integer(start_unicode as i64));
1663 w_array.push(Object::Integer(end_unicode as i64));
1664 w_array.push(Object::Integer(pdf_width));
1665 }
1666
1667 i = j;
1668 }
1669
1670 return w_array;
1671 }
1672 }
1673 }
1674
1675 let ranges = vec![
1677 (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), ];
1714
1715 for (start, end, width) in ranges {
1717 if start == end {
1718 w_array.push(Object::Integer(start));
1720 w_array.push(Object::Array(vec![Object::Integer(width)]));
1721 } else {
1722 w_array.push(Object::Integer(start));
1724 w_array.push(Object::Integer(end));
1725 w_array.push(Object::Integer(width));
1726 }
1727 }
1728
1729 w_array
1730 }
1731
1732 fn generate_cid_to_gid_map(
1734 &mut self,
1735 font: &crate::fonts::Font,
1736 subset_mapping: Option<&HashMap<u32, u16>>,
1737 ) -> Result<Vec<u8>> {
1738 use crate::text::fonts::truetype::TrueTypeFont;
1739
1740 let cmap_mappings = if let Some(subset_map) = subset_mapping {
1743 subset_map.clone()
1745 } else {
1746 let tt_font = TrueTypeFont::parse(font.data.clone())?;
1748 let cmap_tables = tt_font.parse_cmap()?;
1749
1750 let cmap = cmap_tables
1752 .iter()
1753 .find(|t| t.platform_id == 3 && t.encoding_id == 1) .or_else(|| cmap_tables.iter().find(|t| t.platform_id == 0)) .ok_or_else(|| {
1756 crate::error::PdfError::FontError("No Unicode cmap table found".to_string())
1757 })?;
1758
1759 cmap.mappings.clone()
1760 };
1761
1762 let used_chars = self.document_used_chars.clone().unwrap_or_default();
1769
1770 let max_unicode = if !used_chars.is_empty() {
1772 used_chars
1774 .iter()
1775 .map(|ch| *ch as u32)
1776 .max()
1777 .unwrap_or(0x00FF) .min(0xFFFF) as usize
1779 } else {
1780 cmap_mappings
1782 .keys()
1783 .max()
1784 .copied()
1785 .unwrap_or(0xFFFF)
1786 .min(0xFFFF) as usize
1787 };
1788
1789 let mut map = vec![0u8; (max_unicode + 1) * 2];
1791
1792 let mut sample_mappings = Vec::new();
1794 for (&unicode, &glyph_id) in &cmap_mappings {
1795 if unicode <= max_unicode as u32 {
1796 let idx = (unicode as usize) * 2;
1797 map[idx] = (glyph_id >> 8) as u8;
1799 map[idx + 1] = (glyph_id & 0xFF) as u8;
1800
1801 if unicode == 0x0041 || unicode == 0x0061 || unicode == 0x00E1 || unicode == 0x00F1
1803 {
1804 sample_mappings.push((unicode, glyph_id));
1805 }
1806 }
1807 }
1808
1809 Ok(map)
1810 }
1811
1812 fn generate_tounicode_cmap_from_font(&self, font: &crate::fonts::Font) -> Vec<u8> {
1814 use crate::text::fonts::truetype::TrueTypeFont;
1815
1816 let mut cmap = String::new();
1817
1818 cmap.push_str("/CIDInit /ProcSet findresource begin\n");
1820 cmap.push_str("12 dict begin\n");
1821 cmap.push_str("begincmap\n");
1822 cmap.push_str("/CIDSystemInfo\n");
1823 cmap.push_str("<< /Registry (Adobe)\n");
1824 cmap.push_str(" /Ordering (UCS)\n");
1825 cmap.push_str(" /Supplement 0\n");
1826 cmap.push_str(">> def\n");
1827 cmap.push_str("/CMapName /Adobe-Identity-UCS def\n");
1828 cmap.push_str("/CMapType 2 def\n");
1829 cmap.push_str("1 begincodespacerange\n");
1830 cmap.push_str("<0000> <FFFF>\n");
1831 cmap.push_str("endcodespacerange\n");
1832
1833 let mut mappings = Vec::new();
1835 let mut has_font_mappings = false;
1836
1837 if let Ok(tt_font) = TrueTypeFont::parse(font.data.clone()) {
1838 if let Ok(cmap_tables) = tt_font.parse_cmap() {
1839 if let Some(cmap_table) = cmap_tables
1841 .iter()
1842 .find(|t| t.platform_id == 3 && t.encoding_id == 1) .or_else(|| cmap_tables.iter().find(|t| t.platform_id == 0))
1844 {
1846 for (&unicode, &glyph_id) in &cmap_table.mappings {
1849 if glyph_id > 0 && unicode <= 0xFFFF {
1850 mappings.push((unicode, unicode));
1853 }
1854 }
1855 has_font_mappings = true;
1856 }
1857 }
1858 }
1859
1860 if !has_font_mappings {
1862 for i in 0x0020..=0x00FF {
1864 mappings.push((i, i));
1865 }
1866
1867 for i in 0x0100..=0x017F {
1869 mappings.push((i, i));
1870 }
1871
1872 for i in 0x3040..=0x309F {
1875 mappings.push((i, i));
1876 }
1877
1878 for i in 0x30A0..=0x30FF {
1880 mappings.push((i, i));
1881 }
1882
1883 for i in 0x4E00..=0x9FFF {
1885 mappings.push((i, i));
1886 }
1887
1888 for i in 0xAC00..=0xD7AF {
1890 mappings.push((i, i));
1891 }
1892
1893 for i in 0x2000..=0x206F {
1895 mappings.push((i, i));
1896 }
1897
1898 for i in 0x2200..=0x22FF {
1900 mappings.push((i, i));
1901 }
1902
1903 for i in 0x2190..=0x21FF {
1905 mappings.push((i, i));
1906 }
1907
1908 for i in 0x2500..=0x259F {
1910 mappings.push((i, i));
1911 }
1912
1913 for i in 0x25A0..=0x25FF {
1915 mappings.push((i, i));
1916 }
1917
1918 for i in 0x2600..=0x26FF {
1920 mappings.push((i, i));
1921 }
1922 }
1923
1924 mappings.sort_by_key(|&(cid, _)| cid);
1926
1927 let mut i = 0;
1929 while i < mappings.len() {
1930 let start_cid = mappings[i].0;
1932 let start_unicode = mappings[i].1;
1933 let mut end_idx = i;
1934
1935 while end_idx + 1 < mappings.len()
1937 && mappings[end_idx + 1].0 == mappings[end_idx].0 + 1
1938 && mappings[end_idx + 1].1 == mappings[end_idx].1 + 1
1939 && end_idx - i < 99
1940 {
1942 end_idx += 1;
1943 }
1944
1945 if end_idx > i {
1946 cmap.push_str("1 beginbfrange\n");
1948 cmap.push_str(&format!(
1949 "<{:04X}> <{:04X}> <{:04X}>\n",
1950 start_cid, mappings[end_idx].0, start_unicode
1951 ));
1952 cmap.push_str("endbfrange\n");
1953 i = end_idx + 1;
1954 } else {
1955 let mut chars = Vec::new();
1957 let chunk_end = (i + 100).min(mappings.len());
1958
1959 for item in &mappings[i..chunk_end] {
1960 chars.push(*item);
1961 }
1962
1963 if !chars.is_empty() {
1964 cmap.push_str(&format!("{} beginbfchar\n", chars.len()));
1965 for (cid, unicode) in chars {
1966 cmap.push_str(&format!("<{:04X}> <{:04X}>\n", cid, unicode));
1967 }
1968 cmap.push_str("endbfchar\n");
1969 }
1970
1971 i = chunk_end;
1972 }
1973 }
1974
1975 cmap.push_str("endcmap\n");
1977 cmap.push_str("CMapName currentdict /CMap defineresource pop\n");
1978 cmap.push_str("end\n");
1979 cmap.push_str("end\n");
1980
1981 cmap.into_bytes()
1982 }
1983
1984 #[allow(dead_code)]
1986 fn write_truetype_font(
1987 &mut self,
1988 font_name: &str,
1989 font: &crate::text::font_manager::CustomFont,
1990 ) -> Result<ObjectId> {
1991 let font_id = self.allocate_object_id();
1993 let descriptor_id = self.allocate_object_id();
1994 let font_file_id = self.allocate_object_id();
1995
1996 if let Some(ref data) = font.font_data {
1998 let mut font_file_dict = Dictionary::new();
1999 font_file_dict.set("Length1", Object::Integer(data.len() as i64));
2000 let font_stream_obj = Object::Stream(font_file_dict, data.clone());
2001 self.write_object(font_file_id, font_stream_obj)?;
2002 }
2003
2004 let mut descriptor = Dictionary::new();
2006 descriptor.set("Type", Object::Name("FontDescriptor".to_string()));
2007 descriptor.set("FontName", Object::Name(font_name.to_string()));
2008 descriptor.set("Flags", Object::Integer(32)); descriptor.set(
2010 "FontBBox",
2011 Object::Array(vec![
2012 Object::Integer(-1000),
2013 Object::Integer(-1000),
2014 Object::Integer(2000),
2015 Object::Integer(2000),
2016 ]),
2017 );
2018 descriptor.set("ItalicAngle", Object::Integer(0));
2019 descriptor.set("Ascent", Object::Integer(font.descriptor.ascent as i64));
2020 descriptor.set("Descent", Object::Integer(font.descriptor.descent as i64));
2021 descriptor.set(
2022 "CapHeight",
2023 Object::Integer(font.descriptor.cap_height as i64),
2024 );
2025 descriptor.set("StemV", Object::Integer(font.descriptor.stem_v as i64));
2026 descriptor.set("FontFile2", Object::Reference(font_file_id));
2027 self.write_object(descriptor_id, Object::Dictionary(descriptor))?;
2028
2029 let mut font_dict = Dictionary::new();
2031 font_dict.set("Type", Object::Name("Font".to_string()));
2032 font_dict.set("Subtype", Object::Name("TrueType".to_string()));
2033 font_dict.set("BaseFont", Object::Name(font_name.to_string()));
2034 font_dict.set("FirstChar", Object::Integer(0));
2035 font_dict.set("LastChar", Object::Integer(255));
2036
2037 let widths: Vec<Object> = (0..256).map(|_| Object::Integer(600)).collect();
2039 font_dict.set("Widths", Object::Array(widths));
2040 font_dict.set("FontDescriptor", Object::Reference(descriptor_id));
2041
2042 font_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
2044
2045 self.write_object(font_id, Object::Dictionary(font_dict))?;
2046
2047 Ok(font_id)
2048 }
2049
2050 fn write_pages(
2051 &mut self,
2052 document: &Document,
2053 font_refs: &HashMap<String, ObjectId>,
2054 ) -> Result<()> {
2055 let pages_id = self.get_pages_id()?;
2056 let mut pages_dict = Dictionary::new();
2057 pages_dict.set("Type", Object::Name("Pages".to_string()));
2058 pages_dict.set("Count", Object::Integer(document.pages.len() as i64));
2059
2060 let mut kids = Vec::new();
2061
2062 let mut page_ids = Vec::new();
2064 let mut content_ids = Vec::new();
2065 for _ in 0..document.pages.len() {
2066 page_ids.push(self.allocate_object_id());
2067 content_ids.push(self.allocate_object_id());
2068 }
2069
2070 for page_id in &page_ids {
2071 kids.push(Object::Reference(*page_id));
2072 }
2073
2074 pages_dict.set("Kids", Object::Array(kids));
2075
2076 self.write_object(pages_id, Object::Dictionary(pages_dict))?;
2077
2078 self.page_ids = page_ids.clone();
2080
2081 for (i, page) in document.pages.iter().enumerate() {
2083 let page_id = page_ids[i];
2084 let content_id = content_ids[i];
2085
2086 self.write_page_with_fonts(page_id, pages_id, content_id, page, document, font_refs)?;
2087 self.write_page_content(content_id, page)?;
2088 }
2089
2090 Ok(())
2091 }
2092
2093 #[allow(dead_code)]
2095 fn write_pages_with_fonts(
2096 &mut self,
2097 document: &Document,
2098 font_refs: &HashMap<String, ObjectId>,
2099 ) -> Result<()> {
2100 self.write_pages(document, font_refs)
2101 }
2102
2103 fn write_page_with_fonts(
2104 &mut self,
2105 page_id: ObjectId,
2106 parent_id: ObjectId,
2107 content_id: ObjectId,
2108 page: &crate::page::Page,
2109 _document: &Document,
2110 font_refs: &HashMap<String, ObjectId>,
2111 ) -> Result<()> {
2112 let mut page_dict = page.to_dict();
2114
2115 page_dict.set("Type", Object::Name("Page".to_string()));
2116 page_dict.set("Parent", Object::Reference(parent_id));
2117 page_dict.set("Contents", Object::Reference(content_id));
2118
2119 let mut resources = if let Some(Object::Dictionary(res)) = page_dict.get("Resources") {
2121 res.clone()
2122 } else {
2123 Dictionary::new()
2124 };
2125
2126 let mut font_dict = Dictionary::new();
2128
2129 let mut helvetica_dict = Dictionary::new();
2134 helvetica_dict.set("Type", Object::Name("Font".to_string()));
2135 helvetica_dict.set("Subtype", Object::Name("Type1".to_string()));
2136 helvetica_dict.set("BaseFont", Object::Name("Helvetica".to_string()));
2137 helvetica_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
2138 font_dict.set("Helvetica", Object::Dictionary(helvetica_dict));
2139
2140 let mut helvetica_bold_dict = Dictionary::new();
2141 helvetica_bold_dict.set("Type", Object::Name("Font".to_string()));
2142 helvetica_bold_dict.set("Subtype", Object::Name("Type1".to_string()));
2143 helvetica_bold_dict.set("BaseFont", Object::Name("Helvetica-Bold".to_string()));
2144 helvetica_bold_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
2145 font_dict.set("Helvetica-Bold", Object::Dictionary(helvetica_bold_dict));
2146
2147 let mut helvetica_oblique_dict = Dictionary::new();
2148 helvetica_oblique_dict.set("Type", Object::Name("Font".to_string()));
2149 helvetica_oblique_dict.set("Subtype", Object::Name("Type1".to_string()));
2150 helvetica_oblique_dict.set("BaseFont", Object::Name("Helvetica-Oblique".to_string()));
2151 helvetica_oblique_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
2152 font_dict.set(
2153 "Helvetica-Oblique",
2154 Object::Dictionary(helvetica_oblique_dict),
2155 );
2156
2157 let mut helvetica_bold_oblique_dict = Dictionary::new();
2158 helvetica_bold_oblique_dict.set("Type", Object::Name("Font".to_string()));
2159 helvetica_bold_oblique_dict.set("Subtype", Object::Name("Type1".to_string()));
2160 helvetica_bold_oblique_dict.set(
2161 "BaseFont",
2162 Object::Name("Helvetica-BoldOblique".to_string()),
2163 );
2164 helvetica_bold_oblique_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
2165 font_dict.set(
2166 "Helvetica-BoldOblique",
2167 Object::Dictionary(helvetica_bold_oblique_dict),
2168 );
2169
2170 let mut times_dict = Dictionary::new();
2172 times_dict.set("Type", Object::Name("Font".to_string()));
2173 times_dict.set("Subtype", Object::Name("Type1".to_string()));
2174 times_dict.set("BaseFont", Object::Name("Times-Roman".to_string()));
2175 times_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
2176 font_dict.set("Times-Roman", Object::Dictionary(times_dict));
2177
2178 let mut times_bold_dict = Dictionary::new();
2179 times_bold_dict.set("Type", Object::Name("Font".to_string()));
2180 times_bold_dict.set("Subtype", Object::Name("Type1".to_string()));
2181 times_bold_dict.set("BaseFont", Object::Name("Times-Bold".to_string()));
2182 times_bold_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
2183 font_dict.set("Times-Bold", Object::Dictionary(times_bold_dict));
2184
2185 let mut times_italic_dict = Dictionary::new();
2186 times_italic_dict.set("Type", Object::Name("Font".to_string()));
2187 times_italic_dict.set("Subtype", Object::Name("Type1".to_string()));
2188 times_italic_dict.set("BaseFont", Object::Name("Times-Italic".to_string()));
2189 times_italic_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
2190 font_dict.set("Times-Italic", Object::Dictionary(times_italic_dict));
2191
2192 let mut times_bold_italic_dict = Dictionary::new();
2193 times_bold_italic_dict.set("Type", Object::Name("Font".to_string()));
2194 times_bold_italic_dict.set("Subtype", Object::Name("Type1".to_string()));
2195 times_bold_italic_dict.set("BaseFont", Object::Name("Times-BoldItalic".to_string()));
2196 times_bold_italic_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
2197 font_dict.set(
2198 "Times-BoldItalic",
2199 Object::Dictionary(times_bold_italic_dict),
2200 );
2201
2202 let mut courier_dict = Dictionary::new();
2204 courier_dict.set("Type", Object::Name("Font".to_string()));
2205 courier_dict.set("Subtype", Object::Name("Type1".to_string()));
2206 courier_dict.set("BaseFont", Object::Name("Courier".to_string()));
2207 courier_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
2208 font_dict.set("Courier", Object::Dictionary(courier_dict));
2209
2210 let mut courier_bold_dict = Dictionary::new();
2211 courier_bold_dict.set("Type", Object::Name("Font".to_string()));
2212 courier_bold_dict.set("Subtype", Object::Name("Type1".to_string()));
2213 courier_bold_dict.set("BaseFont", Object::Name("Courier-Bold".to_string()));
2214 courier_bold_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
2215 font_dict.set("Courier-Bold", Object::Dictionary(courier_bold_dict));
2216
2217 let mut courier_oblique_dict = Dictionary::new();
2218 courier_oblique_dict.set("Type", Object::Name("Font".to_string()));
2219 courier_oblique_dict.set("Subtype", Object::Name("Type1".to_string()));
2220 courier_oblique_dict.set("BaseFont", Object::Name("Courier-Oblique".to_string()));
2221 courier_oblique_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
2222 font_dict.set("Courier-Oblique", Object::Dictionary(courier_oblique_dict));
2223
2224 let mut courier_bold_oblique_dict = Dictionary::new();
2225 courier_bold_oblique_dict.set("Type", Object::Name("Font".to_string()));
2226 courier_bold_oblique_dict.set("Subtype", Object::Name("Type1".to_string()));
2227 courier_bold_oblique_dict.set("BaseFont", Object::Name("Courier-BoldOblique".to_string()));
2228 courier_bold_oblique_dict.set("Encoding", Object::Name("WinAnsiEncoding".to_string()));
2229 font_dict.set(
2230 "Courier-BoldOblique",
2231 Object::Dictionary(courier_bold_oblique_dict),
2232 );
2233
2234 for (font_name, font_id) in font_refs {
2236 font_dict.set(font_name, Object::Reference(*font_id));
2237 }
2238
2239 resources.set("Font", Object::Dictionary(font_dict));
2240
2241 let has_images = !page.images().is_empty();
2243 let has_forms = !page.form_xobjects().is_empty();
2244
2245 if has_images || has_forms {
2246 let mut xobject_dict = Dictionary::new();
2247
2248 for (name, image) in page.images() {
2249 let image_id = self.allocate_object_id();
2251
2252 if image.has_transparency() {
2254 let (mut main_obj, smask_obj) = image.to_pdf_object_with_transparency()?;
2256
2257 if let Some(smask_stream) = smask_obj {
2259 let smask_id = self.allocate_object_id();
2260 self.write_object(smask_id, smask_stream)?;
2261
2262 if let Object::Stream(ref mut dict, _) = main_obj {
2264 dict.set("SMask", Object::Reference(smask_id));
2265 }
2266 }
2267
2268 self.write_object(image_id, main_obj)?;
2270 } else {
2271 self.write_object(image_id, image.to_pdf_object())?;
2273 }
2274
2275 xobject_dict.set(name, Object::Reference(image_id));
2277 }
2278
2279 for (name, form) in page.form_xobjects() {
2281 let form_id = self.allocate_object_id();
2282 let stream = form.to_stream()?;
2283 let stream_obj =
2284 Object::Stream(stream.dictionary().clone(), stream.data().to_vec());
2285 self.write_object(form_id, stream_obj)?;
2286 xobject_dict.set(name, Object::Reference(form_id));
2287 }
2288
2289 resources.set("XObject", Object::Dictionary(xobject_dict));
2290 }
2291
2292 if let Some(extgstate_states) = page.get_extgstate_resources() {
2294 let mut extgstate_dict = Dictionary::new();
2295 for (name, state) in extgstate_states {
2296 let mut state_dict = Dictionary::new();
2297 state_dict.set("Type", Object::Name("ExtGState".to_string()));
2298
2299 if let Some(alpha_stroke) = state.alpha_stroke {
2301 state_dict.set("CA", Object::Real(alpha_stroke));
2302 }
2303 if let Some(alpha_fill) = state.alpha_fill {
2304 state_dict.set("ca", Object::Real(alpha_fill));
2305 }
2306
2307 if let Some(line_width) = state.line_width {
2309 state_dict.set("LW", Object::Real(line_width));
2310 }
2311 if let Some(line_cap) = state.line_cap {
2312 state_dict.set("LC", Object::Integer(line_cap as i64));
2313 }
2314 if let Some(line_join) = state.line_join {
2315 state_dict.set("LJ", Object::Integer(line_join as i64));
2316 }
2317 if let Some(dash_pattern) = &state.dash_pattern {
2318 let dash_objects: Vec<Object> = dash_pattern
2319 .array
2320 .iter()
2321 .map(|&d| Object::Real(d))
2322 .collect();
2323 state_dict.set(
2324 "D",
2325 Object::Array(vec![
2326 Object::Array(dash_objects),
2327 Object::Real(dash_pattern.phase),
2328 ]),
2329 );
2330 }
2331
2332 extgstate_dict.set(name, Object::Dictionary(state_dict));
2333 }
2334 if !extgstate_dict.is_empty() {
2335 resources.set("ExtGState", Object::Dictionary(extgstate_dict));
2336 }
2337 }
2338
2339 if let Some(preserved_res) = page.get_preserved_resources() {
2342 let mut preserved_writer_dict = self.convert_pdf_objects_dict_to_writer(preserved_res);
2344
2345 if let Some(Object::Dictionary(fonts)) = preserved_writer_dict.get("Font") {
2347 let renamed_fonts = crate::writer::rename_preserved_fonts(fonts);
2349
2350 preserved_writer_dict.set("Font", Object::Dictionary(renamed_fonts));
2352 }
2353
2354 if let Some(Object::Dictionary(fonts)) = preserved_writer_dict.get("Font") {
2358 let mut fonts_with_refs = crate::objects::Dictionary::new();
2359
2360 for (font_name, font_obj) in fonts.iter() {
2361 if let Object::Dictionary(font_dict) = font_obj {
2362 let updated_font = self.write_embedded_font_streams(font_dict)?;
2364 fonts_with_refs.set(font_name, Object::Dictionary(updated_font));
2365 } else {
2366 fonts_with_refs.set(font_name, font_obj.clone());
2368 }
2369 }
2370
2371 preserved_writer_dict.set("Font", Object::Dictionary(fonts_with_refs));
2373 }
2374
2375 if let Some(Object::Dictionary(xobjects)) = preserved_writer_dict.get("XObject") {
2379 let mut xobjects_with_refs = crate::objects::Dictionary::new();
2380 tracing::debug!(
2381 "Externalizing {} preserved XObject entries as indirect objects",
2382 xobjects.len()
2383 );
2384
2385 for (xobj_name, xobj_obj) in xobjects.iter() {
2386 match xobj_obj {
2387 Object::Stream(dict, data) => {
2388 let obj_id = self.allocate_object_id();
2389 self.write_object(obj_id, Object::Stream(dict.clone(), data.clone()))?;
2390 xobjects_with_refs.set(xobj_name, Object::Reference(obj_id));
2391 }
2392 Object::Dictionary(dict) => {
2393 let externalized = self.externalize_streams_in_dict(dict)?;
2395 xobjects_with_refs.set(xobj_name, Object::Dictionary(externalized));
2396 }
2397 _ => {
2398 xobjects_with_refs.set(xobj_name, xobj_obj.clone());
2399 }
2400 }
2401 }
2402
2403 preserved_writer_dict.set("XObject", Object::Dictionary(xobjects_with_refs));
2404 }
2405
2406 for (key, value) in preserved_writer_dict.iter() {
2408 if let Some(Object::Dictionary(existing)) = resources.get(key) {
2410 if let Object::Dictionary(preserved_dict) = value {
2411 let mut merged = existing.clone();
2412 for (res_name, res_obj) in preserved_dict.iter() {
2414 if !merged.contains_key(res_name) {
2415 merged.set(res_name, res_obj.clone());
2416 }
2417 }
2418 resources.set(key, Object::Dictionary(merged));
2419 }
2420 } else {
2421 resources.set(key, value.clone());
2423 }
2424 }
2425 }
2426
2427 page_dict.set("Resources", Object::Dictionary(resources));
2428
2429 if let Some(Object::Array(annots)) = page_dict.get("Annots") {
2431 let mut new_annots = Vec::new();
2432
2433 for annot in annots {
2434 if let Object::Dictionary(ref annot_dict) = annot {
2435 if let Some(Object::Name(subtype)) = annot_dict.get("Subtype") {
2436 if subtype == "Widget" {
2437 let widget_id = self.allocate_object_id();
2439 self.write_object(widget_id, annot.clone())?;
2440 new_annots.push(Object::Reference(widget_id));
2441
2442 if let Some(Object::Name(_ft)) = annot_dict.get("FT") {
2444 if let Some(Object::String(field_name)) = annot_dict.get("T") {
2445 self.field_widget_map
2446 .entry(field_name.clone())
2447 .or_default()
2448 .push(widget_id);
2449 self.field_id_map.insert(field_name.clone(), widget_id);
2450 self.form_field_ids.push(widget_id);
2451 }
2452 }
2453 continue;
2454 }
2455 }
2456 }
2457 new_annots.push(annot.clone());
2458 }
2459
2460 if !new_annots.is_empty() {
2461 page_dict.set("Annots", Object::Array(new_annots));
2462 }
2463 }
2464
2465 self.write_object(page_id, Object::Dictionary(page_dict))?;
2466 Ok(())
2467 }
2468}
2469
2470impl PdfWriter<BufWriter<std::fs::File>> {
2471 pub fn new(path: impl AsRef<Path>) -> Result<Self> {
2472 let file = std::fs::File::create(path)?;
2473 let writer = BufWriter::new(file);
2474
2475 Ok(Self {
2476 writer,
2477 xref_positions: HashMap::new(),
2478 current_position: 0,
2479 next_object_id: 1,
2480 catalog_id: None,
2481 pages_id: None,
2482 info_id: None,
2483 field_widget_map: HashMap::new(),
2484 field_id_map: HashMap::new(),
2485 form_field_ids: Vec::new(),
2486 page_ids: Vec::new(),
2487 config: WriterConfig::default(),
2488 document_used_chars: None,
2489 buffered_objects: HashMap::new(),
2490 compressed_object_map: HashMap::new(),
2491 prev_xref_offset: None,
2492 base_pdf_size: None,
2493 encrypt_obj_id: None,
2494 file_id: None,
2495 encryption_state: None,
2496 pending_encrypt_dict: None,
2497 })
2498 }
2499}
2500
2501impl<W: Write> PdfWriter<W> {
2502 fn externalize_streams_in_dict(
2521 &mut self,
2522 dict: &crate::objects::Dictionary,
2523 ) -> Result<crate::objects::Dictionary> {
2524 let mut result = crate::objects::Dictionary::new();
2525 for (key, value) in dict.iter() {
2526 match value {
2527 Object::Stream(d, data) => {
2528 let obj_id = self.allocate_object_id();
2529 self.write_object(obj_id, Object::Stream(d.clone(), data.clone()))?;
2530 result.set(key, Object::Reference(obj_id));
2531 }
2532 _ => {
2533 result.set(key, value.clone());
2534 }
2535 }
2536 }
2537 Ok(result)
2538 }
2539
2540 fn write_embedded_font_streams(
2541 &mut self,
2542 font_dict: &crate::objects::Dictionary,
2543 ) -> Result<crate::objects::Dictionary> {
2544 let mut updated_font = font_dict.clone();
2545
2546 if let Some(Object::Name(subtype)) = font_dict.get("Subtype") {
2548 if subtype == "Type0" {
2549 if let Some(Object::Array(descendants)) = font_dict.get("DescendantFonts") {
2551 let mut updated_descendants = Vec::new();
2552
2553 for descendant in descendants {
2554 match descendant {
2555 Object::Dictionary(cidfont) => {
2556 let updated_cidfont =
2558 self.write_cidfont_embedded_streams(cidfont)?;
2559 let cidfont_id = self.allocate_object_id();
2561 self.write_object(cidfont_id, Object::Dictionary(updated_cidfont))?;
2562 updated_descendants.push(Object::Reference(cidfont_id));
2564 }
2565 Object::Reference(_) => {
2566 updated_descendants.push(descendant.clone());
2568 }
2569 _ => {
2570 updated_descendants.push(descendant.clone());
2571 }
2572 }
2573 }
2574
2575 updated_font.set("DescendantFonts", Object::Array(updated_descendants));
2576 }
2577
2578 if let Some(Object::Stream(stream_dict, stream_data)) = font_dict.get("ToUnicode") {
2580 let tounicode_id = self.allocate_object_id();
2581 self.write_object(
2582 tounicode_id,
2583 Object::Stream(stream_dict.clone(), stream_data.clone()),
2584 )?;
2585 updated_font.set("ToUnicode", Object::Reference(tounicode_id));
2586 }
2587
2588 return Ok(updated_font);
2589 }
2590 }
2591
2592 if let Some(Object::Dictionary(descriptor)) = font_dict.get("FontDescriptor") {
2595 let mut updated_descriptor = descriptor.clone();
2596 let font_file_keys = ["FontFile", "FontFile2", "FontFile3"];
2597
2598 for key in &font_file_keys {
2600 if let Some(Object::Stream(stream_dict, stream_data)) = descriptor.get(*key) {
2601 let stream_id = self.allocate_object_id();
2603 let stream_obj = Object::Stream(stream_dict.clone(), stream_data.clone());
2604 self.write_object(stream_id, stream_obj)?;
2605
2606 updated_descriptor.set(*key, Object::Reference(stream_id));
2608 }
2609 }
2611
2612 updated_font.set("FontDescriptor", Object::Dictionary(updated_descriptor));
2614 }
2615
2616 Ok(updated_font)
2617 }
2618
2619 fn write_cidfont_embedded_streams(
2621 &mut self,
2622 cidfont: &crate::objects::Dictionary,
2623 ) -> Result<crate::objects::Dictionary> {
2624 let mut updated_cidfont = cidfont.clone();
2625
2626 if let Some(Object::Dictionary(descriptor)) = cidfont.get("FontDescriptor") {
2628 let mut updated_descriptor = descriptor.clone();
2629 let font_file_keys = ["FontFile", "FontFile2", "FontFile3"];
2630
2631 for key in &font_file_keys {
2633 if let Some(Object::Stream(stream_dict, stream_data)) = descriptor.get(*key) {
2634 let stream_id = self.allocate_object_id();
2635 self.write_object(
2636 stream_id,
2637 Object::Stream(stream_dict.clone(), stream_data.clone()),
2638 )?;
2639 updated_descriptor.set(*key, Object::Reference(stream_id));
2640 }
2641 }
2642
2643 let descriptor_id = self.allocate_object_id();
2645 self.write_object(descriptor_id, Object::Dictionary(updated_descriptor))?;
2646
2647 updated_cidfont.set("FontDescriptor", Object::Reference(descriptor_id));
2649 }
2650
2651 if let Some(Object::Stream(map_dict, map_data)) = cidfont.get("CIDToGIDMap") {
2653 let map_id = self.allocate_object_id();
2654 self.write_object(map_id, Object::Stream(map_dict.clone(), map_data.clone()))?;
2655 updated_cidfont.set("CIDToGIDMap", Object::Reference(map_id));
2656 }
2657
2658 Ok(updated_cidfont)
2659 }
2660
2661 fn allocate_object_id(&mut self) -> ObjectId {
2662 let id = ObjectId::new(self.next_object_id, 0);
2663 self.next_object_id += 1;
2664 id
2665 }
2666
2667 fn get_catalog_id(&self) -> Result<ObjectId> {
2669 self.catalog_id.ok_or_else(|| {
2670 PdfError::InvalidOperation(
2671 "catalog_id not initialized - write_document() must be called first".to_string(),
2672 )
2673 })
2674 }
2675
2676 fn get_pages_id(&self) -> Result<ObjectId> {
2678 self.pages_id.ok_or_else(|| {
2679 PdfError::InvalidOperation(
2680 "pages_id not initialized - write_document() must be called first".to_string(),
2681 )
2682 })
2683 }
2684
2685 fn get_info_id(&self) -> Result<ObjectId> {
2687 self.info_id.ok_or_else(|| {
2688 PdfError::InvalidOperation(
2689 "info_id not initialized - write_document() must be called first".to_string(),
2690 )
2691 })
2692 }
2693
2694 fn write_object(&mut self, id: ObjectId, object: Object) -> Result<()> {
2695 use crate::writer::ObjectStreamWriter;
2696
2697 let object = if let Some(ref enc_state) = self.encryption_state {
2699 let mut obj = object;
2700 enc_state.encryptor.encrypt_object(&mut obj, &id)?;
2701 obj
2702 } else {
2703 object
2704 };
2705
2706 if self.config.use_object_streams && ObjectStreamWriter::can_compress(&object) {
2708 let mut buffer = Vec::new();
2709 self.write_object_value_to_buffer(&object, &mut buffer)?;
2710 self.buffered_objects.insert(id, buffer);
2711 return Ok(());
2712 }
2713
2714 self.xref_positions.insert(id, self.current_position);
2716
2717 let header = format!("{} {} obj\n", id.number(), id.generation());
2719 self.write_bytes(header.as_bytes())?;
2720
2721 self.write_object_value(&object)?;
2722
2723 self.write_bytes(b"\nendobj\n")?;
2724 Ok(())
2725 }
2726
2727 fn write_object_value(&mut self, object: &Object) -> Result<()> {
2728 match object {
2729 Object::Null => self.write_bytes(b"null")?,
2730 Object::Boolean(b) => self.write_bytes(if *b { b"true" } else { b"false" })?,
2731 Object::Integer(i) => self.write_bytes(i.to_string().as_bytes())?,
2732 Object::Real(f) => self.write_bytes(
2733 format!("{f:.6}")
2734 .trim_end_matches('0')
2735 .trim_end_matches('.')
2736 .as_bytes(),
2737 )?,
2738 Object::String(s) => {
2739 self.write_bytes(b"(")?;
2740 self.write_bytes(s.as_bytes())?;
2741 self.write_bytes(b")")?;
2742 }
2743 Object::ByteString(bytes) => {
2744 self.write_bytes(b"<")?;
2746 for byte in bytes {
2747 self.write_bytes(format!("{byte:02X}").as_bytes())?;
2748 }
2749 self.write_bytes(b">")?;
2750 }
2751 Object::Name(n) => {
2752 self.write_bytes(b"/")?;
2753 self.write_bytes(n.as_bytes())?;
2754 }
2755 Object::Array(arr) => {
2756 self.write_bytes(b"[")?;
2757 for (i, obj) in arr.iter().enumerate() {
2758 if i > 0 {
2759 self.write_bytes(b" ")?;
2760 }
2761 self.write_object_value(obj)?;
2762 }
2763 self.write_bytes(b"]")?;
2764 }
2765 Object::Dictionary(dict) => {
2766 self.write_bytes(b"<<")?;
2767 for (key, value) in dict.entries() {
2768 self.write_bytes(b"\n/")?;
2769 self.write_bytes(key.as_bytes())?;
2770 self.write_bytes(b" ")?;
2771 self.write_object_value(value)?;
2772 }
2773 self.write_bytes(b"\n>>")?;
2774 }
2775 Object::Stream(dict, data) => {
2776 let mut corrected_dict = dict.clone();
2779 corrected_dict.set("Length", Object::Integer(data.len() as i64));
2780
2781 self.write_object_value(&Object::Dictionary(corrected_dict))?;
2782 self.write_bytes(b"\nstream\n")?;
2783 self.write_bytes(data)?;
2784 self.write_bytes(b"\nendstream")?;
2785 }
2786 Object::Reference(id) => {
2787 let ref_str = format!("{} {} R", id.number(), id.generation());
2788 self.write_bytes(ref_str.as_bytes())?;
2789 }
2790 }
2791 Ok(())
2792 }
2793
2794 fn write_object_value_to_buffer(&self, object: &Object, buffer: &mut Vec<u8>) -> Result<()> {
2796 match object {
2797 Object::Null => buffer.extend_from_slice(b"null"),
2798 Object::Boolean(b) => buffer.extend_from_slice(if *b { b"true" } else { b"false" }),
2799 Object::Integer(i) => buffer.extend_from_slice(i.to_string().as_bytes()),
2800 Object::Real(f) => buffer.extend_from_slice(
2801 format!("{f:.6}")
2802 .trim_end_matches('0')
2803 .trim_end_matches('.')
2804 .as_bytes(),
2805 ),
2806 Object::String(s) => {
2807 buffer.push(b'(');
2808 buffer.extend_from_slice(s.as_bytes());
2809 buffer.push(b')');
2810 }
2811 Object::ByteString(bytes) => {
2812 buffer.push(b'<');
2813 for byte in bytes {
2814 buffer.extend_from_slice(format!("{byte:02X}").as_bytes());
2815 }
2816 buffer.push(b'>');
2817 }
2818 Object::Name(n) => {
2819 buffer.push(b'/');
2820 buffer.extend_from_slice(n.as_bytes());
2821 }
2822 Object::Array(arr) => {
2823 buffer.push(b'[');
2824 for (i, obj) in arr.iter().enumerate() {
2825 if i > 0 {
2826 buffer.push(b' ');
2827 }
2828 self.write_object_value_to_buffer(obj, buffer)?;
2829 }
2830 buffer.push(b']');
2831 }
2832 Object::Dictionary(dict) => {
2833 buffer.extend_from_slice(b"<<");
2834 for (key, value) in dict.entries() {
2835 buffer.extend_from_slice(b"\n/");
2836 buffer.extend_from_slice(key.as_bytes());
2837 buffer.push(b' ');
2838 self.write_object_value_to_buffer(value, buffer)?;
2839 }
2840 buffer.extend_from_slice(b"\n>>");
2841 }
2842 Object::Stream(_, _) => {
2843 return Err(crate::error::PdfError::ObjectStreamError(
2845 "Cannot compress stream objects in object streams".to_string(),
2846 ));
2847 }
2848 Object::Reference(id) => {
2849 let ref_str = format!("{} {} R", id.number(), id.generation());
2850 buffer.extend_from_slice(ref_str.as_bytes());
2851 }
2852 }
2853 Ok(())
2854 }
2855
2856 fn flush_object_streams(&mut self) -> Result<()> {
2858 if self.buffered_objects.is_empty() {
2859 return Ok(());
2860 }
2861
2862 let config = ObjectStreamConfig {
2864 max_objects_per_stream: 100,
2865 compression_level: 6,
2866 enabled: true,
2867 };
2868 let mut os_writer = ObjectStreamWriter::new(config);
2869
2870 let mut buffered: Vec<_> = self.buffered_objects.iter().collect();
2872 buffered.sort_by_key(|(id, _)| id.number());
2873
2874 for (id, data) in buffered {
2876 os_writer.add_object(*id, data.clone())?;
2877 }
2878
2879 let streams = os_writer.finalize()?;
2881
2882 for mut stream in streams {
2884 let stream_id = stream.stream_id;
2885
2886 let compressed_data = stream.generate_stream_data(6)?;
2888
2889 let dict = stream.generate_dictionary(&compressed_data);
2891
2892 for (index, (obj_id, _)) in stream.objects.iter().enumerate() {
2894 self.compressed_object_map
2895 .insert(*obj_id, (stream_id, index as u32));
2896 }
2897
2898 self.xref_positions.insert(stream_id, self.current_position);
2900
2901 let header = format!("{} {} obj\n", stream_id.number(), stream_id.generation());
2902 self.write_bytes(header.as_bytes())?;
2903
2904 self.write_object_value(&Object::Dictionary(dict))?;
2905
2906 self.write_bytes(b"\nstream\n")?;
2907 self.write_bytes(&compressed_data)?;
2908 self.write_bytes(b"\nendstream\nendobj\n")?;
2909 }
2910
2911 Ok(())
2912 }
2913
2914 fn write_xref(&mut self) -> Result<()> {
2915 self.write_bytes(b"xref\n")?;
2916
2917 let mut entries: Vec<_> = self
2919 .xref_positions
2920 .iter()
2921 .map(|(id, pos)| (*id, *pos))
2922 .collect();
2923 entries.sort_by_key(|(id, _)| id.number());
2924
2925 let max_obj_num = entries.iter().map(|(id, _)| id.number()).max().unwrap_or(0);
2927
2928 self.write_bytes(b"0 ")?;
2931 self.write_bytes((max_obj_num + 1).to_string().as_bytes())?;
2932 self.write_bytes(b"\n")?;
2933
2934 self.write_bytes(b"0000000000 65535 f \n")?;
2936
2937 for obj_num in 1..=max_obj_num {
2940 let _obj_id = ObjectId::new(obj_num, 0);
2941 if let Some((_, position)) = entries.iter().find(|(id, _)| id.number() == obj_num) {
2942 let entry = format!("{:010} {:05} n \n", position, 0);
2943 self.write_bytes(entry.as_bytes())?;
2944 } else {
2945 self.write_bytes(b"0000000000 00000 f \n")?;
2947 }
2948 }
2949
2950 Ok(())
2951 }
2952
2953 fn write_xref_stream(&mut self) -> Result<()> {
2954 let catalog_id = self.get_catalog_id()?;
2955 let info_id = self.get_info_id()?;
2956
2957 let xref_stream_id = self.allocate_object_id();
2959 let xref_position = self.current_position;
2960
2961 let mut xref_writer = XRefStreamWriter::new(xref_stream_id);
2963 xref_writer.set_trailer_info(catalog_id, info_id);
2964
2965 xref_writer.add_free_entry(0, 65535);
2967
2968 let mut entries: Vec<_> = self
2970 .xref_positions
2971 .iter()
2972 .map(|(id, pos)| (*id, *pos))
2973 .collect();
2974 entries.sort_by_key(|(id, _)| id.number());
2975
2976 let max_obj_num = entries
2978 .iter()
2979 .map(|(id, _)| id.number())
2980 .max()
2981 .unwrap_or(0)
2982 .max(xref_stream_id.number());
2983
2984 for obj_num in 1..=max_obj_num {
2986 let obj_id = ObjectId::new(obj_num, 0);
2987
2988 if obj_num == xref_stream_id.number() {
2989 xref_writer.add_in_use_entry(xref_position, 0);
2991 } else if let Some((stream_id, index)) = self.compressed_object_map.get(&obj_id) {
2992 xref_writer.add_compressed_entry(stream_id.number(), *index);
2994 } else if let Some((id, position)) =
2995 entries.iter().find(|(id, _)| id.number() == obj_num)
2996 {
2997 xref_writer.add_in_use_entry(*position, id.generation());
2999 } else {
3000 xref_writer.add_free_entry(0, 0);
3002 }
3003 }
3004
3005 self.xref_positions.insert(xref_stream_id, xref_position);
3007
3008 self.write_bytes(
3010 format!(
3011 "{} {} obj\n",
3012 xref_stream_id.number(),
3013 xref_stream_id.generation()
3014 )
3015 .as_bytes(),
3016 )?;
3017
3018 let uncompressed_data = xref_writer.encode_entries();
3020 let final_data = if self.config.compress_streams {
3021 crate::compression::compress(&uncompressed_data)?
3022 } else {
3023 uncompressed_data
3024 };
3025
3026 let mut dict = xref_writer.create_dictionary(None);
3028 dict.set("Length", Object::Integer(final_data.len() as i64));
3029
3030 if self.config.compress_streams {
3032 dict.set("Filter", Object::Name("FlateDecode".to_string()));
3033 }
3034 self.write_bytes(b"<<")?;
3035 for (key, value) in dict.iter() {
3036 self.write_bytes(b"\n/")?;
3037 self.write_bytes(key.as_bytes())?;
3038 self.write_bytes(b" ")?;
3039 self.write_object_value(value)?;
3040 }
3041 self.write_bytes(b"\n>>\n")?;
3042
3043 self.write_bytes(b"stream\n")?;
3045 self.write_bytes(&final_data)?;
3046 self.write_bytes(b"\nendstream\n")?;
3047 self.write_bytes(b"endobj\n")?;
3048
3049 self.write_bytes(b"\nstartxref\n")?;
3051 self.write_bytes(xref_position.to_string().as_bytes())?;
3052 self.write_bytes(b"\n%%EOF\n")?;
3053
3054 Ok(())
3055 }
3056
3057 fn init_encryption(&mut self, encryption: &crate::document::DocumentEncryption) -> Result<()> {
3064 use crate::encryption::{
3065 CryptFilterManager, CryptFilterMethod, FunctionalCryptFilter, ObjectEncryptor,
3066 };
3067 use std::sync::Arc;
3068
3069 let mut fid = vec![0u8; 16];
3071 use rand::Rng;
3072 rand::rng().fill_bytes(&mut fid);
3073
3074 let enc_dict = encryption
3075 .create_encryption_dict(Some(&fid))
3076 .map_err(|e| PdfError::EncryptionError(format!("encryption dict: {}", e)))?;
3077
3078 let enc_key = encryption
3080 .get_encryption_key(&enc_dict, Some(&fid))
3081 .map_err(|e| PdfError::EncryptionError(format!("encryption key: {}", e)))?;
3082
3083 let handler = encryption.handler();
3085 let (method, key_len) = match encryption.strength {
3086 crate::document::EncryptionStrength::Rc4_40bit => (CryptFilterMethod::V2, Some(5)),
3087 crate::document::EncryptionStrength::Rc4_128bit => (CryptFilterMethod::V2, Some(16)),
3088 crate::document::EncryptionStrength::Aes128 => (CryptFilterMethod::AESV2, Some(16)),
3089 crate::document::EncryptionStrength::Aes256 => (CryptFilterMethod::AESV3, Some(32)),
3090 };
3091
3092 let std_filter = FunctionalCryptFilter {
3093 name: "StdCF".to_string(),
3094 method,
3095 length: key_len,
3096 auth_event: crate::encryption::AuthEvent::DocOpen,
3097 recipients: None,
3098 };
3099
3100 let mut filter_manager =
3101 CryptFilterManager::new(Box::new(handler), "StdCF".to_string(), "StdCF".to_string());
3102 filter_manager.add_filter(std_filter);
3103
3104 let encryptor =
3105 ObjectEncryptor::new(Arc::new(filter_manager), enc_key, enc_dict.encrypt_metadata);
3106
3107 let encrypt_id = self.allocate_object_id();
3109 self.encrypt_obj_id = Some(encrypt_id);
3110 self.file_id = Some(fid);
3111 self.encryption_state = Some(WriterEncryptionState { encryptor });
3112
3113 self.pending_encrypt_dict = Some(enc_dict.to_dict());
3115
3116 Ok(())
3117 }
3118
3119 fn write_encryption_dict(&mut self) -> Result<()> {
3121 if let (Some(encrypt_id), Some(dict)) =
3122 (self.encrypt_obj_id, self.pending_encrypt_dict.take())
3123 {
3124 let enc_state = self.encryption_state.take();
3126 self.write_object(encrypt_id, Object::Dictionary(dict))?;
3127 self.encryption_state = enc_state;
3128 }
3129 Ok(())
3130 }
3131
3132 fn write_trailer(&mut self, xref_position: u64) -> Result<()> {
3133 let catalog_id = self.get_catalog_id()?;
3134 let info_id = self.get_info_id()?;
3135 let max_obj_num = self
3137 .xref_positions
3138 .keys()
3139 .map(|id| id.number())
3140 .max()
3141 .unwrap_or(0);
3142
3143 let mut trailer = Dictionary::new();
3144 trailer.set("Size", Object::Integer((max_obj_num + 1) as i64));
3145 trailer.set("Root", Object::Reference(catalog_id));
3146 trailer.set("Info", Object::Reference(info_id));
3147
3148 if let Some(prev_xref) = self.prev_xref_offset {
3150 trailer.set("Prev", Object::Integer(prev_xref as i64));
3151 }
3152
3153 if let Some(encrypt_id) = self.encrypt_obj_id {
3155 trailer.set("Encrypt", Object::Reference(encrypt_id));
3156 }
3157 if let Some(ref fid) = self.file_id {
3158 trailer.set(
3159 "ID",
3160 Object::Array(vec![
3161 Object::ByteString(fid.clone()),
3162 Object::ByteString(fid.clone()),
3163 ]),
3164 );
3165 }
3166
3167 self.write_bytes(b"trailer\n")?;
3168 self.write_object_value(&Object::Dictionary(trailer))?;
3169 self.write_bytes(b"\nstartxref\n")?;
3170 self.write_bytes(xref_position.to_string().as_bytes())?;
3171 self.write_bytes(b"\n%%EOF\n")?;
3172
3173 Ok(())
3174 }
3175
3176 fn write_bytes(&mut self, data: &[u8]) -> Result<()> {
3177 self.writer.write_all(data)?;
3178 self.current_position += data.len() as u64;
3179 Ok(())
3180 }
3181
3182 #[allow(dead_code)]
3183 fn create_widget_appearance_stream(&mut self, widget_dict: &Dictionary) -> Result<ObjectId> {
3184 let rect = if let Some(Object::Array(rect_array)) = widget_dict.get("Rect") {
3186 if rect_array.len() >= 4 {
3187 if let (
3188 Some(Object::Real(x1)),
3189 Some(Object::Real(y1)),
3190 Some(Object::Real(x2)),
3191 Some(Object::Real(y2)),
3192 ) = (
3193 rect_array.first(),
3194 rect_array.get(1),
3195 rect_array.get(2),
3196 rect_array.get(3),
3197 ) {
3198 (*x1, *y1, *x2, *y2)
3199 } else {
3200 (0.0, 0.0, 100.0, 20.0) }
3202 } else {
3203 (0.0, 0.0, 100.0, 20.0) }
3205 } else {
3206 (0.0, 0.0, 100.0, 20.0) };
3208
3209 let width = rect.2 - rect.0;
3210 let height = rect.3 - rect.1;
3211
3212 let mut content = String::new();
3214
3215 content.push_str("q\n");
3217
3218 content.push_str("0 0 0 RG\n"); content.push_str("1 w\n"); content.push_str(&format!("0 0 {width} {height} re\n"));
3224 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));
3229 content.push_str("f\n"); content.push_str("Q\n");
3233
3234 let mut stream_dict = Dictionary::new();
3236 stream_dict.set("Type", Object::Name("XObject".to_string()));
3237 stream_dict.set("Subtype", Object::Name("Form".to_string()));
3238 stream_dict.set(
3239 "BBox",
3240 Object::Array(vec![
3241 Object::Real(0.0),
3242 Object::Real(0.0),
3243 Object::Real(width),
3244 Object::Real(height),
3245 ]),
3246 );
3247 stream_dict.set("Resources", Object::Dictionary(Dictionary::new()));
3248 stream_dict.set("Length", Object::Integer(content.len() as i64));
3249
3250 let stream_id = self.allocate_object_id();
3252 self.write_object(stream_id, Object::Stream(stream_dict, content.into_bytes()))?;
3253
3254 Ok(stream_id)
3255 }
3256
3257 #[allow(dead_code)]
3258 fn create_field_appearance_stream(
3259 &mut self,
3260 field_dict: &Dictionary,
3261 widget: &crate::forms::Widget,
3262 ) -> Result<ObjectId> {
3263 let width = widget.rect.upper_right.x - widget.rect.lower_left.x;
3264 let height = widget.rect.upper_right.y - widget.rect.lower_left.y;
3265
3266 let mut content = String::new();
3268
3269 content.push_str("q\n");
3271
3272 if let Some(bg_color) = &widget.appearance.background_color {
3274 match bg_color {
3275 crate::graphics::Color::Gray(g) => {
3276 content.push_str(&format!("{g} g\n"));
3277 }
3278 crate::graphics::Color::Rgb(r, g, b) => {
3279 content.push_str(&format!("{r} {g} {b} rg\n"));
3280 }
3281 crate::graphics::Color::Cmyk(c, m, y, k) => {
3282 content.push_str(&format!("{c} {m} {y} {k} k\n"));
3283 }
3284 }
3285 content.push_str(&format!("0 0 {width} {height} re\n"));
3286 content.push_str("f\n");
3287 }
3288
3289 if let Some(border_color) = &widget.appearance.border_color {
3291 match border_color {
3292 crate::graphics::Color::Gray(g) => {
3293 content.push_str(&format!("{g} G\n"));
3294 }
3295 crate::graphics::Color::Rgb(r, g, b) => {
3296 content.push_str(&format!("{r} {g} {b} RG\n"));
3297 }
3298 crate::graphics::Color::Cmyk(c, m, y, k) => {
3299 content.push_str(&format!("{c} {m} {y} {k} K\n"));
3300 }
3301 }
3302 content.push_str(&format!("{} w\n", widget.appearance.border_width));
3303 content.push_str(&format!("0 0 {width} {height} re\n"));
3304 content.push_str("S\n");
3305 }
3306
3307 if let Some(Object::Name(ft)) = field_dict.get("FT") {
3309 if ft == "Btn" {
3310 if let Some(Object::Name(v)) = field_dict.get("V") {
3311 if v == "Yes" {
3312 content.push_str("0 0 0 RG\n"); content.push_str("2 w\n");
3315 let margin = width * 0.2;
3316 content.push_str(&format!("{} {} m\n", margin, height / 2.0));
3317 content.push_str(&format!("{} {} l\n", width / 2.0, margin));
3318 content.push_str(&format!("{} {} l\n", width - margin, height - margin));
3319 content.push_str("S\n");
3320 }
3321 }
3322 }
3323 }
3324
3325 content.push_str("Q\n");
3327
3328 let mut stream_dict = Dictionary::new();
3330 stream_dict.set("Type", Object::Name("XObject".to_string()));
3331 stream_dict.set("Subtype", Object::Name("Form".to_string()));
3332 stream_dict.set(
3333 "BBox",
3334 Object::Array(vec![
3335 Object::Real(0.0),
3336 Object::Real(0.0),
3337 Object::Real(width),
3338 Object::Real(height),
3339 ]),
3340 );
3341 stream_dict.set("Resources", Object::Dictionary(Dictionary::new()));
3342 stream_dict.set("Length", Object::Integer(content.len() as i64));
3343
3344 let stream_id = self.allocate_object_id();
3346 self.write_object(stream_id, Object::Stream(stream_dict, content.into_bytes()))?;
3347
3348 Ok(stream_id)
3349 }
3350}
3351
3352fn format_pdf_date(date: DateTime<Utc>) -> String {
3354 let formatted = date.format("D:%Y%m%d%H%M%S");
3357
3358 format!("{formatted}+00'00")
3360}
3361
3362#[cfg(test)]
3363mod tests;
3364
3365#[cfg(test)]
3366mod rigorous_tests;