1pub mod pdf {
2 use std::{ffi::CString, fmt, io, mem, ptr};
3
4 use crate::Canvas;
5
6 use skia_bindings::{
7 self as sb, SkPDF_AttributeList, SkPDF_DateTime, SkPDF_Metadata, SkPDF_StructureElementNode,
8 };
9
10 use crate::{
11 interop::{AsStr, RustWStream, SetStr},
12 prelude::*,
13 scalar, Document, MILESTONE,
14 };
15
16 pub type AttributeList = Handle<SkPDF_AttributeList>;
17 unsafe_send_sync!(AttributeList);
18
19 impl NativeDrop for SkPDF_AttributeList {
20 fn drop(&mut self) {
21 unsafe { sb::C_SkPDF_AttributeList_destruct(self) }
22 }
23 }
24
25 impl Default for AttributeList {
26 fn default() -> Self {
27 AttributeList::from_native_c(unsafe { SkPDF_AttributeList::new() })
28 }
29 }
30
31 impl fmt::Debug for AttributeList {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 f.debug_struct("AttributeList").finish()
34 }
35 }
36
37 impl AttributeList {
43 pub fn append_int(
44 &mut self,
45 owner: impl AsRef<str>,
46 name: impl AsRef<str>,
47 value: i32,
48 ) -> &mut Self {
49 let owner = CString::new(owner.as_ref()).unwrap();
50 let name = CString::new(name.as_ref()).unwrap();
51 unsafe {
52 self.native_mut()
53 .appendInt(owner.as_ptr(), name.as_ptr(), value)
54 }
55 self
56 }
57
58 pub fn append_float(
59 &mut self,
60 owner: impl AsRef<str>,
61 name: impl AsRef<str>,
62 value: f32,
63 ) -> &mut Self {
64 let owner = CString::new(owner.as_ref()).unwrap();
65 let name = CString::new(name.as_ref()).unwrap();
66 unsafe {
67 self.native_mut()
68 .appendFloat(owner.as_ptr(), name.as_ptr(), value)
69 }
70 self
71 }
72
73 pub fn append_float_array(
74 &mut self,
75 owner: impl AsRef<str>,
76 name: impl AsRef<str>,
77 value: &[f32],
78 ) -> &mut Self {
79 let owner = CString::new(owner.as_ref()).unwrap();
80 let name = CString::new(name.as_ref()).unwrap();
81 unsafe {
82 sb::C_SkPDF_AttributeList_appendFloatArray(
83 self.native_mut(),
84 owner.as_ptr(),
85 name.as_ptr(),
86 value.as_ptr(),
87 value.len(),
88 )
89 }
90 self
91 }
92 }
93
94 #[repr(transparent)]
95 pub struct StructureElementNode(ptr::NonNull<SkPDF_StructureElementNode>);
96
97 impl NativeAccess for StructureElementNode {
98 type Native = SkPDF_StructureElementNode;
99
100 fn native(&self) -> &SkPDF_StructureElementNode {
101 unsafe { self.0.as_ref() }
102 }
103 fn native_mut(&mut self) -> &mut SkPDF_StructureElementNode {
104 unsafe { self.0.as_mut() }
105 }
106 }
107
108 impl Drop for StructureElementNode {
109 fn drop(&mut self) {
110 unsafe { sb::C_SkPDF_StructureElementNode_delete(self.native_mut()) }
111 }
112 }
113
114 impl Default for StructureElementNode {
115 fn default() -> Self {
116 Self(ptr::NonNull::new(unsafe { sb::C_SkPDF_StructureElementNode_new() }).unwrap())
117 }
118 }
119
120 impl fmt::Debug for StructureElementNode {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 f.debug_struct("StructureElementNode")
123 .field("type_string", &self.type_string())
124 .field("child_vector", &self.child_vector())
125 .field("node_id", &self.node_id())
126 .field("attributes", &self.attributes())
127 .field("alt", &self.alt())
128 .field("lang", &self.lang())
129 .finish()
130 }
131 }
132
133 impl StructureElementNode {
138 pub fn new(type_string: impl AsRef<str>) -> Self {
139 let mut node = Self::default();
140 node.set_type_string(type_string);
141 node
142 }
143
144 pub fn set_type_string(&mut self, type_string: impl AsRef<str>) -> &mut Self {
145 self.native_mut().fTypeString.set_str(type_string);
146 self
147 }
148
149 pub fn type_string(&self) -> &str {
150 self.native().fTypeString.as_str()
151 }
152
153 pub fn set_child_vector(
154 &mut self,
155 mut child_vector: Vec<StructureElementNode>,
156 ) -> &mut Self {
157 unsafe {
159 sb::C_SkPDF_StructureElementNode_setChildVector(
160 self.native_mut(),
161 child_vector.as_mut_ptr() as _,
162 child_vector.len(),
163 )
164 }
165 self
166 }
167
168 pub fn append_child(&mut self, node: StructureElementNode) -> &mut Self {
169 unsafe {
170 sb::C_SkPDF_StructElementNode_appendChild(self.native_mut(), node.0.as_ptr());
171 }
172 mem::forget(node);
173 self
174 }
175
176 pub fn child_vector(&self) -> &[StructureElementNode] {
177 let mut ptr = ptr::null();
178 unsafe {
179 let len = sb::C_SkPDF_StructureElementNode_getChildVector(self.native(), &mut ptr);
180 safer::from_raw_parts(ptr as _, len)
181 }
182 }
183
184 pub fn set_node_id(&mut self, node_id: i32) -> &mut Self {
185 self.native_mut().fNodeId = node_id;
186 self
187 }
188
189 pub fn node_id(&self) -> i32 {
190 self.native().fNodeId
191 }
192
193 pub fn attributes(&self) -> &AttributeList {
194 AttributeList::from_native_ref(&self.native().fAttributes)
195 }
196
197 pub fn attributes_mut(&mut self) -> &mut AttributeList {
198 AttributeList::from_native_ref_mut(&mut self.native_mut().fAttributes)
199 }
200
201 pub fn set_alt(&mut self, alt: impl AsRef<str>) -> &mut Self {
202 self.native_mut().fAlt.set_str(alt);
203 self
204 }
205
206 pub fn alt(&self) -> &str {
207 self.native().fAlt.as_str()
208 }
209
210 pub fn set_lang(&mut self, lang: impl AsRef<str>) -> &mut Self {
211 self.native_mut().fLang.set_str(lang);
212 self
213 }
214
215 pub fn lang(&self) -> &str {
216 self.native().fLang.as_str()
217 }
218 }
219
220 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
221 #[repr(C)]
222 pub struct DateTime {
223 pub time_zone_minutes: i16,
225 pub year: u16,
227 pub month: u8,
229 pub day_of_week: u8,
231 pub day: u8,
233 pub hour: u8,
235 pub minute: u8,
237 pub second: u8,
239 }
240
241 native_transmutable!(SkPDF_DateTime, DateTime, date_time_layout);
242
243 #[derive(Debug)]
245 pub struct Metadata {
246 pub title: String,
248 pub author: String,
250 pub subject: String,
252 pub keywords: String,
255 pub creator: String,
258 pub producer: String,
260 pub creation: Option<DateTime>,
262 pub modified: Option<DateTime>,
264 pub lang: String,
268 pub raster_dpi: Option<scalar>,
275 pub pdf_a: bool,
279 pub encoding_quality: Option<i32>,
284
285 pub structure_element_tree_root: Option<StructureElementNode>,
286
287 pub outline: Outline,
288
289 pub compression_level: CompressionLevel,
292 }
293
294 impl Default for Metadata {
295 fn default() -> Self {
296 Self {
297 title: Default::default(),
298 author: Default::default(),
299 subject: Default::default(),
300 keywords: Default::default(),
301 creator: Default::default(),
302 producer: format!("Skia/PDF m{MILESTONE}"),
303 creation: Default::default(),
304 modified: Default::default(),
305 lang: Default::default(),
306 raster_dpi: Default::default(),
307 pdf_a: Default::default(),
308 encoding_quality: Default::default(),
309 structure_element_tree_root: None,
310 outline: Outline::None,
311 compression_level: Default::default(),
312 }
313 }
314 }
315
316 pub type Outline = skia_bindings::SkPDF_Metadata_Outline;
317 variant_name!(Outline::StructureElements);
318
319 pub type CompressionLevel = skia_bindings::SkPDF_Metadata_CompressionLevel;
320 variant_name!(CompressionLevel::HighButSlow);
321
322 pub fn new_document<'a>(
330 writer: &'a mut impl io::Write,
331 metadata: Option<&Metadata>,
332 ) -> Document<'a> {
333 let mut md = InternalMetadata::default();
334 if let Some(metadata) = metadata {
335 let internal = md.native_mut();
336 internal.fTitle.set_str(&metadata.title);
337 internal.fAuthor.set_str(&metadata.author);
338 internal.fSubject.set_str(&metadata.subject);
339 internal.fKeywords.set_str(&metadata.keywords);
340 internal.fCreator.set_str(&metadata.creator);
341 internal.fProducer.set_str(&metadata.producer);
342 if let Some(creation) = metadata.creation {
343 internal.fCreation = creation.into_native();
344 }
345 if let Some(modified) = metadata.modified {
346 internal.fModified = modified.into_native();
347 }
348 internal.fLang.set_str(&metadata.lang);
349 if let Some(raster_dpi) = metadata.raster_dpi {
350 internal.fRasterDPI = raster_dpi;
351 }
352 internal.fPDFA = metadata.pdf_a;
353 if let Some(encoding_quality) = metadata.encoding_quality {
354 internal.fEncodingQuality = encoding_quality
355 }
356 if let Some(structure_element_tree) = &metadata.structure_element_tree_root {
357 internal.fStructureElementTreeRoot = structure_element_tree.0.as_ptr();
358 }
359 internal.fOutline = metadata.outline;
360 internal.fCompressionLevel = metadata.compression_level
361 }
362
363 #[cfg(all(feature = "textlayout", feature = "embed-icudtl"))]
365 crate::icu::init();
366
367 let mut stream = RustWStream::new(writer);
368 let document = RCHandle::from_ptr(unsafe {
369 sb::C_SkPDF_MakeDocument(stream.stream_mut(), md.native())
370 })
371 .unwrap();
372
373 Document::new(stream, document)
374 }
375
376 type InternalMetadata = Handle<SkPDF_Metadata>;
381
382 impl NativeDrop for SkPDF_Metadata {
383 fn drop(&mut self) {
384 unsafe { sb::C_SkPDF_Metadata_destruct(self) }
385 }
386 }
387
388 impl Default for Handle<SkPDF_Metadata> {
389 fn default() -> Self {
390 Self::construct(|pdf_md| unsafe { sb::C_SkPDF_Metadata_Construct(pdf_md) })
391 }
392 }
393
394 pub mod node_id {
395 pub const NOTHING: i32 = 0;
396 pub const OTHER_ARTIFACT: i32 = -1;
397 pub const PAGINATION_ARTIFACT: i32 = -2;
398 pub const PAGINATION_HEADER_ARTIFACT: i32 = -3;
399 pub const PAGINATION_FOOTER_ARTIFACT: i32 = -4;
400 pub const PAGINATION_WATERMARK_ARTIFACT: i32 = -5;
401 pub const LAYOUT_ARTIFACT: i32 = -6;
402 pub const PAGE_ARTIFACT: i32 = -7;
403 pub const BACKGROUND_ARTIFACT: i32 = -8;
404 }
405
406 pub fn set_node_id(canvas: &Canvas, node_id: i32) {
407 unsafe {
408 sb::C_SkPDF_SetNodeId(canvas.native_mut(), node_id);
409 }
410 }
411}
412
413#[cfg(test)]
414mod tests {
415 use crate::pdf::StructureElementNode;
416
417 use super::pdf;
418
419 #[test]
420 fn create_attribute_list() {
421 let mut _al = pdf::AttributeList::default();
422 _al.append_float_array("Owner", "Name", &[1.0, 2.0, 3.0]);
423 }
424
425 #[test]
426 fn structure_element_node_child_vector() {
427 let mut root = StructureElementNode::new("root");
428 root.append_child(StructureElementNode::new("nested"));
429 root.append_child(StructureElementNode::new("nested2"));
430 let v = root.child_vector();
431 assert_eq!(v[0].type_string(), "nested");
432 assert_eq!(v[1].type_string(), "nested2");
433 }
434}