zoffixznet / Mojo-PDF

PDF generating Perl 5 module with the Mojo goodness!
1 stars 2 forks source link

Is it possible to get the PDF data into a variable? #12

Open 0xAF opened 4 years ago

0xAF commented 4 years ago

Since using Mojolicious, it is desirable to get the PDF data into a variable, so it can be used in $c->render(data => $pdf_data, format => 'pdf'); later. I've been looking into this, but I did not found a way to do it and looking into PDF::Reuse, it seems not possible. Please advice.

s1037989 commented 4 years ago

I agree that given how PDF::Reuse is built that this isn't possible. I agree that getting the PDF data into a data variable would be nice, or specifically not forcing the use of a file on disk. PDFs can get pretty large, so perhaps the design decision was to avoid excessive memory consumption. Nevertheless, perhaps one solution would be for Mojo::PDF, in the absence of the mandatory filename argument to new(), could generate a tempfile and after calling end() could then slurp the contents and return the bytes or store them in an attribute.

That said, it's simple enough to render the PDF with reply->file:

get '/' => sub ($c) {
  my $file = Mojo::File::tempfile(SUFFIX => '.pdf');
  my $pdf = Mojo::PDF->new($file)->end;
  return $c->reply->file($file);
};

I think a nice feature addition to Mojo::PDF would be to not require a filename argument to new, and when that occurs, generate a Mojo::File::tempfile() and store the path in an attribute which can then later be called. The result might allow for:

get '/' => sub ($c) {
  my $pdf = Mojo::PDF->new->end;
  return $c->reply->file($pdf->file);
};
0xAF commented 4 years ago

Thanks for the answer. Yes, I agree with you about the internal (to Mojo::PDF) temp file. Sounds like a good addition. My concern with temp files was the housekeeping. We would need to remove the tempfiles, and I assume in some weird cases they will be left on disk. Then I imagine external (cronjob perhaps) script (or internal Mojo Timer) would need to clean the files based on their creation date or something.

Thanks for the hints anyway. It was helpful.

s1037989 commented 4 years ago

Required housekeeping would be annoying; fortunately, File::Temp already takes care of that for you! After all, it is a temp file. ;)

See File::Temp#OBJECT-ORIENTED-INTERFACE DESTROY method:

When the object goes out of scope, the destructor is called. This destructor will attempt to unlink the file if the constructor was called with UNLINK set to 1 (the default state if UNLINK is not specified).

If the object has been passed to a child process during a fork, the file will be deleted when the object goes out of scope in the parent.

0xAF commented 4 years ago

Thanks for the hint. I was thinking for out-of-scope deletion of the file... but I was going to investigate on this tonight. :)

zoffixznet commented 3 years ago

Turns out this is possible out of the box, because (though undocumented) PDF::Reuse has logic to handle IO::String objects. This is in addition to documented handling of STDOUT if filename is undef.

I added extra documentation in https://github.com/zoffixznet/Mojo-PDF/commit/283badc23154dee62f1fccdeb0cf7ddbd208b6b6

There may be a better way to offer this functionality in Mojo::PDF through some options and methods, so I'll leave this issue open.