pub mod pdf {
use crate::{
interop::{AsStr, DynamicMemoryWStream, SetStr},
prelude::*,
scalar, DateTime, Document,
};
use skia_bindings::{
self as sb, SkPDF_AttributeList, SkPDF_Metadata, SkPDF_StructureElementNode,
};
use std::{ffi::CString, fmt, mem, ptr};
pub type AttributeList = Handle<SkPDF_AttributeList>;
unsafe_send_sync!(AttributeList);
impl NativeDrop for SkPDF_AttributeList {
fn drop(&mut self) {
unsafe { sb::C_SkPDF_AttributeList_destruct(self) }
}
}
impl Default for AttributeList {
fn default() -> Self {
AttributeList::from_native_c(unsafe { SkPDF_AttributeList::new() })
}
}
impl fmt::Debug for AttributeList {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AttributeList").finish()
}
}
impl AttributeList {
pub fn append_int(
&mut self,
owner: impl AsRef<str>,
name: impl AsRef<str>,
value: i32,
) -> &mut Self {
let owner = CString::new(owner.as_ref()).unwrap();
let name = CString::new(name.as_ref()).unwrap();
unsafe {
self.native_mut()
.appendInt(owner.as_ptr(), name.as_ptr(), value)
}
self
}
pub fn append_float(
&mut self,
owner: impl AsRef<str>,
name: impl AsRef<str>,
value: f32,
) -> &mut Self {
let owner = CString::new(owner.as_ref()).unwrap();
let name = CString::new(name.as_ref()).unwrap();
unsafe {
self.native_mut()
.appendFloat(owner.as_ptr(), name.as_ptr(), value)
}
self
}
pub fn append_float_array(
&mut self,
owner: impl AsRef<str>,
name: impl AsRef<str>,
value: &[f32],
) -> &mut Self {
let owner = CString::new(owner.as_ref()).unwrap();
let name = CString::new(name.as_ref()).unwrap();
unsafe {
sb::C_SkPDF_AttributeList_appendFloatArray(
self.native_mut(),
owner.as_ptr(),
name.as_ptr(),
value.as_ptr(),
value.len(),
)
}
self
}
}
#[repr(transparent)]
pub struct StructureElementNode(ptr::NonNull<SkPDF_StructureElementNode>);
impl NativeAccess for StructureElementNode {
type Native = SkPDF_StructureElementNode;
fn native(&self) -> &SkPDF_StructureElementNode {
unsafe { self.0.as_ref() }
}
fn native_mut(&mut self) -> &mut SkPDF_StructureElementNode {
unsafe { self.0.as_mut() }
}
}
impl Drop for StructureElementNode {
fn drop(&mut self) {
unsafe { sb::C_SkPDF_StructureElementNode_delete(self.native_mut()) }
}
}
impl Default for StructureElementNode {
fn default() -> Self {
Self::new("")
}
}
impl fmt::Debug for StructureElementNode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("StructureElementNode")
.field("type_string", &self.type_string())
.field("child_vector", &self.child_vector())
.field("node_id", &self.node_id())
.field("attributes", &self.attributes())
.field("alt", &self.alt())
.field("lang", &self.lang())
.finish()
}
}
impl StructureElementNode {
pub fn new(type_string: impl AsRef<str>) -> Self {
let mut node = Self::default();
node.set_type_string(type_string);
node
}
pub fn set_type_string(&mut self, type_string: impl AsRef<str>) -> &mut Self {
self.native_mut().fTypeString.set_str(type_string);
self
}
pub fn type_string(&self) -> &str {
self.native().fTypeString.as_str()
}
pub fn set_child_vector(
&mut self,
mut child_vector: Vec<StructureElementNode>,
) -> &mut Self {
unsafe {
sb::C_SkPDF_StructureElementNode_setChildVector(
self.native_mut(),
child_vector.as_mut_ptr() as _,
child_vector.len(),
)
}
self
}
pub fn append_child(&mut self, node: StructureElementNode) -> &mut Self {
unsafe {
sb::C_SkPDF_StructElementNode_appendChild(self.native_mut(), node.0.as_ptr());
}
mem::forget(node);
self
}
pub fn child_vector(&self) -> &[StructureElementNode] {
let mut ptr = ptr::null_mut();
unsafe {
let len = sb::C_SkPDF_StructureElementNode_getChildVector(self.native(), &mut ptr);
safer::from_raw_parts(ptr as _, len)
}
}
pub fn set_node_id(&mut self, node_id: i32) -> &mut Self {
self.native_mut().fNodeId = node_id;
self
}
pub fn node_id(&self) -> i32 {
self.native().fNodeId
}
pub fn attributes(&self) -> &AttributeList {
AttributeList::from_native_ref(&self.native().fAttributes)
}
pub fn attributes_mut(&mut self) -> &mut AttributeList {
AttributeList::from_native_ref_mut(&mut self.native_mut().fAttributes)
}
pub fn set_alt(&mut self, alt: impl AsRef<str>) -> &mut Self {
self.native_mut().fAlt.set_str(alt);
self
}
pub fn alt(&self) -> &str {
self.native().fAlt.as_str()
}
pub fn set_lang(&mut self, lang: impl AsRef<str>) -> &mut Self {
self.native_mut().fLang.set_str(lang);
self
}
pub fn lang(&self) -> &str {
self.native().fLang.as_str()
}
}
#[derive(Default, Debug)]
pub struct Metadata {
pub title: String,
pub author: String,
pub subject: String,
pub keywords: String,
pub creator: String,
pub producer: String,
pub creation: Option<DateTime>,
pub modified: Option<DateTime>,
pub raster_dpi: Option<scalar>,
pub pdfa: bool,
pub encoding_quality: Option<i32>,
structure_element_tree_root: Option<StructureElementNode>,
}
pub fn new_document(metadata: Option<&Metadata>) -> Document {
let mut md = InternalMetadata::default();
if let Some(metadata) = metadata {
let internal = md.native_mut();
internal.fTitle.set_str(&metadata.title);
internal.fAuthor.set_str(&metadata.author);
internal.fSubject.set_str(&metadata.subject);
internal.fKeywords.set_str(&metadata.keywords);
internal.fCreator.set_str(&metadata.creator);
internal.fProducer.set_str(&metadata.producer);
if let Some(creation) = metadata.creation {
internal.fCreation = creation.into_native();
}
if let Some(modified) = metadata.modified {
internal.fModified = modified.into_native();
}
if let Some(raster_dpi) = metadata.raster_dpi {
internal.fRasterDPI = raster_dpi;
}
internal.fPDFA = metadata.pdfa;
if let Some(encoding_quality) = metadata.encoding_quality {
internal.fEncodingQuality = encoding_quality
}
if let Some(_structure_element_tree_root) = &metadata.structure_element_tree_root {
unimplemented!("");
}
}
#[cfg(all(feature = "textlayout", feature = "embed-icudtl"))]
crate::icu::init();
let mut memory_stream = Box::pin(DynamicMemoryWStream::new());
let document = RCHandle::from_ptr(unsafe {
sb::C_SkPDF_MakeDocument(memory_stream.native_mut().base_mut(), md.native())
})
.unwrap();
Document::new(memory_stream, document)
}
type InternalMetadata = Handle<SkPDF_Metadata>;
impl NativeDrop for SkPDF_Metadata {
fn drop(&mut self) {
unsafe { sb::C_SkPDF_Metadata_destruct(self) }
}
}
impl Default for Handle<SkPDF_Metadata> {
fn default() -> Self {
Self::construct(|pdf_md| unsafe { sb::C_SkPDF_Metadata_Construct(pdf_md) })
}
}
}
#[test]
fn create_attribute_list() {
use pdf::AttributeList;
let mut _al = AttributeList::default();
_al.append_float_array("Owner", "Name", &[1.0, 2.0, 3.0]);
}