Skip to content

Dump to any type that implements Write + Seek traits #9

@mariopal

Description

@mariopal

Instead of always writing the generated PDF to a File, I have modified the code a little so that it dumps the result to any type W that implements Write + Seek:

diff --git a/src/fontsource.rs b/src/fontsource.rs
index 5c7f38c..77f2f67 100644
--- a/src/fontsource.rs
+++ b/src/fontsource.rs
@@ -5,7 +5,7 @@ use crate::fontmetrics::{get_builtin_metrics, FontMetrics};
 use crate::Pdf;
 use std::cmp::Eq;
 use std::hash::Hash;
-use std::io::{self, Write};
+use std::io::{self, Write, Seek};

 /// The "Base14" built-in fonts in PDF.
 /// Underscores in these names are hyphens in the real names.
@@ -38,7 +38,7 @@ pub trait FontSource: PartialEq + Eq + Hash {
     ///
     /// This is called automatically for each font used in a document.
     /// There should be no need to call this method from user code.
-    fn write_object(&self, pdf: &mut Pdf) -> io::Result<usize>;
+    fn write_object<W: Write + Seek>(&self, pdf: &mut Pdf<W>) -> io::Result<usize>;

     /// Get the PDF name of this font.
     ///
@@ -80,7 +80,8 @@ pub trait FontSource: PartialEq + Eq + Hash {
 }

 impl FontSource for BuiltinFont {
-    fn write_object(&self, pdf: &mut Pdf) -> io::Result<usize> {
+    fn write_object<W: Write + Seek>(&self, pdf: &mut Pdf<W>) -> io::Result<usize>
+    {
         // Note: This is enough for a Base14 font, other fonts will
         // require a stream for the actual font, and probably another
         // object for metrics etc
diff --git a/src/lib.rs b/src/lib.rs
index 6dd4812..950cc9e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -85,8 +85,8 @@ pub use crate::textobject::TextObject;
 /// are appended with the `render_page` method.
 /// Don't forget to call `finish` when done, to write the document
 /// trailer, without it the written file won't be a proper PDF.
-pub struct Pdf {
-    output: File,
+pub struct Pdf<W> {
+    output: W,
     object_offsets: Vec<i64>,
     page_objects_ids: Vec<usize>,
     all_font_object_ids: HashMap<BuiltinFont, usize>,
@@ -97,15 +97,17 @@ pub struct Pdf {
 const ROOT_OBJECT_ID: usize = 1;
 const PAGES_OBJECT_ID: usize = 2;

-impl Pdf {
+impl Pdf<File> {
     /// Create a new PDF document as a new file with given filename.
-    pub fn create(filename: &str) -> io::Result<Pdf> {
+    pub fn create(filename: &str) -> io::Result<Pdf<File>> {
         let file = File::create(filename)?;
         Pdf::new(file)
     }
+}

+impl<W: Write + Seek> Pdf<W> {
     /// Create a new PDF document, writing to `output`.
-    pub fn new(mut output: File) -> io::Result<Pdf> {
+    pub fn new(mut output: W) -> io::Result<Pdf<W>> {
         // TODO Maybe use a lower version?  Possibly decide by features used?
         output.write_all(b"%PDF-1.7\n%\xB5\xED\xAE\xFB\n")?;
         Ok(Pdf {
@@ -255,7 +257,7 @@ impl Pdf {

     fn write_new_object<F, T>(&mut self, write_content: F) -> io::Result<T>
     where
-        F: FnOnce(usize, &mut Pdf) -> io::Result<T>,
+        F: FnOnce(usize, &mut Pdf<W>) -> io::Result<T>,
     {
         let id = self.object_offsets.len();
         let (result, offset) =
@@ -270,7 +272,7 @@ impl Pdf {
         write_content: F,
     ) -> io::Result<T>
     where
-        F: FnOnce(&mut Pdf) -> io::Result<T>,
+        F: FnOnce(&mut Pdf<W>) -> io::Result<T>,
     {
         assert!(self.object_offsets[id] == -1);
         let (result, offset) = self.write_object(id, write_content)?;
@@ -284,7 +286,7 @@ impl Pdf {
         write_content: F,
     ) -> io::Result<(T, i64)>
     where
-        F: FnOnce(&mut Pdf) -> io::Result<T>,
+        F: FnOnce(&mut Pdf<W>) -> io::Result<T>,
     {
         // `as i64` here would overflow for PDF files bigger than 2**63 bytes
         let offset = self.tell()? as i64;

I only put it here in case you might be interested in adding it to the current code. I think it is compatible with the code that already uses this library. I use it to save the PDF in memory and return it directly as a response to a web request, without going through the file system.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions