File Coverage

blib/lib/Catalyst/View/Wkhtmltopdf.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Catalyst::View::Wkhtmltopdf;
2 1     1   37429 use Moose;
  0            
  0            
3              
4             extends 'Catalyst::View';
5              
6             use version;
7             our $VERSION = qv('0.5.2');
8              
9             use File::Temp;
10             use URI::Escape;
11             use Path::Class;
12             use File::Spec;
13              
14             has 'stash_key' => (
15             is => 'rw',
16             isa => 'Str',
17             lazy => 1,
18             default => sub { 'wk' }
19             );
20             has 'tmpdir' => (
21             is => 'rw',
22             isa => 'Str',
23             lazy => 1,
24             default => sub { File::Spec->tmpdir() }
25             );
26             has 'command' => (
27             is => 'rw',
28             isa => 'Str',
29             lazy => 1,
30             default => sub { '/usr/bin/wkhtmltopdf' }
31             );
32             has 'tt_view' => (
33             is => 'rw',
34             isa => 'Str',
35             lazy => 1,
36             default => sub { 'TT' }
37             );
38             has 'page_size' => (
39             is => 'rw',
40             isa => 'Str',
41             lazy => 1,
42             default => sub { 'a4' }
43             );
44             has 'orientation' => (
45             is => 'rw',
46             isa => 'Str',
47             lazy => 1,
48             default => sub { 'Portrait' }
49             );
50             has 'disposition' => (
51             is => 'rw',
52             isa => 'Str',
53             lazy => 1,
54             default => sub { 'inline' }
55             );
56             has 'filename' => (
57             is => 'rw',
58             isa => 'Str',
59             lazy => 1,
60             default => sub { 'output.pdf' }
61             );
62             has 'allows' => (
63             is => 'rw',
64             isa => 'ArrayRef',
65             lazy => 1,
66             default => sub { [] }
67             );
68              
69             sub process {
70             my ( $self, $c ) = @_;
71              
72             my $wk = $c->stash->{ $self->stash_key };
73              
74             my $pdfcontent = $self->render($c, $wk);
75              
76             my $disposition = $wk->{disposition} || $self->disposition;
77             my $filename = uri_escape_utf8( $wk->{filename} || $self->filename );
78             $c->res->header(
79             'Content-Disposition' => "$disposition; filename*=UTF-8''$filename",
80             'Content-type' => 'application/pdf',
81             );
82             $c->res->body($pdfcontent);
83             }
84              
85             sub render {
86             my ( $self, $c, $args ) = @_;
87            
88             # Arguments for TT view - if not defined those will be the stash
89             # as per C::V::TT documentation
90             if (!$args->{template_args}) { $args->{template_args} = undef }
91            
92             my $html;
93             if ( defined $args->{template} ) {
94             $html = $c->view( $self->tt_view )->render( $c, $args->{template} ) or die;
95             } else {
96             $html = $args->{html};
97             }
98             die 'Void-input' if !defined $html;
99              
100             # Usual page size A4, but labels would need a smaller one so we leave it
101             my $page_size = '--page-size ' . ( $args->{page_size} || $self->page_size );
102              
103             # Page Orientation
104             my $orientation = '--orientation ' . ( $args->{orientation} || $self->orientation );
105              
106             # Custom page size will override the previous
107             if ( defined $args->{page_width} && defined $args->{page_height} ) {
108             $page_size = "--page-width $args->{page_width} --page-height $args->{page_height} ";
109             }
110              
111             # Create a temporary file
112             use File::Temp;
113             my $htmlf = File::Temp->new(
114             DIR => $self->tmpdir,
115             SUFFIX => '.html',
116             UNLINK => 1,
117             );
118             binmode $htmlf, ':utf8';
119             my $htmlfn = $htmlf->filename;
120             my $pdffn = $htmlfn;
121             $pdffn =~ s/\.html/.pdf/;
122              
123             print $htmlf $html;
124              
125             # Build wkhtmltopdf command line
126             my $hcmd = $self->command . ' ' . $page_size . ' ' . $orientation . " ";
127             $hcmd .= "--allow " . $self->tmpdir . " ";
128              
129             for my $allow ( @{ $self->allows } ) {
130             $hcmd .= '--allow ' . $allow . ' ';
131             }
132             $hcmd .= "--margin-top $args->{margin_top} " if exists $args->{margin_top};
133             $hcmd .= "--margin-left $args->{margin_left} " if exists $args->{margin_left};
134             $hcmd .= "--margin-bottom $args->{margin_bottom} " if exists $args->{margin_bottom};
135             $hcmd .= "--margin-right $args->{margin_right} " if exists $args->{margin_right};
136             $hcmd .= " $htmlfn $pdffn";
137              
138             # Create the PDF file
139             my $output = `$hcmd`;
140             die "$! [likely can't find wkhtmltopdf command!]" if $output;
141              
142             # Read the output and return it
143             my $pdffc = Path::Class::File->new($pdffn);
144             my $pdfcontent = $pdffc->slurp();
145             $pdffc->remove();
146            
147             return $pdfcontent;
148             }
149              
150             __PACKAGE__->meta->make_immutable();
151              
152             1;
153              
154             __END__
155              
156             =head1 NAME
157              
158             Catalyst::View::Wkhtmltopdf - Catalyst view to convert HTML (or TT) content to PDF using wkhtmltopdf
159              
160             =head1 SYNOPSIS
161              
162             # lib/MyApp/View/Wkhtmltopdf.pm
163             package MyApp::View::Wkhtmltopdf;
164             use Moose;
165             extends qw/Catalyst::View::Wkhtmltopdf/;
166             __PACKAGE__->meta->make_immutable();
167             1;
168            
169             # configure in lib/MyApp.pm
170             MyApp->config({
171             ...
172             'View::Wkhtmltopdf' => {
173             command => '/usr/local/bin/wkhtmltopdf',
174             # Guessed via File::Spec by default
175             tmpdir => '/usr/tmp',
176             # Name of the Template view, "TT" by default
177             tt_view => 'Template',
178             },
179             });
180            
181             sub ciao : Local {
182             my($self, $c) = @_;
183            
184             # Pass some HTML...
185             $c->stash->{wk} = {
186             html => $web_page,
187             };
188            
189             # ..or a TT template
190             $c->stash->{wk} = {
191             template => 'hello.tt',
192             page_size => 'a5',
193             };
194              
195             # More parameters...
196             $c->stash->{wk} = {
197             html => $web_page,
198             disposition => 'attachment',
199             filename => 'mydocument.pdf',
200             };
201            
202             $c->forward('View::Wkhtmltopdf');
203             }
204              
205             =head1 DESCRIPTION
206              
207             I<Catalyst::View::Wkhtmltopdf> is a L<Catalyst> view handler that
208             converts HTML data to PDF using wkhtmltopdf (which must be installed
209             on your system). It can also handle direct conversion of TT templates
210             (via L<Catalyst::View::TT>).
211              
212             =head1 CONFIG VARIABLES
213              
214             All configuration parameters are optional as they have a default.
215              
216             =over 4
217              
218             =item stash_key
219              
220             The stash key which contains data and optional runtime configuration
221             to pass to the view. Default is I<wk>.
222              
223             =item tmpdir
224              
225             Default: guessed via C<File::Spec::tmpdir()>.
226              
227             Name of URI parameter to specify JSON callback function name. Defaults
228             to C<callback>. Only effective when C<allow_callback> is turned on.
229              
230             =item command
231              
232             Default: C</usr/bin/wkhtmltopdf>.
233              
234             The full path and filename to the wkhtmltopdf command. Defaults to
235             I</usr/bin/wkhtmltopdf>.
236              
237             =item allows
238              
239             Default: the temporary directory.
240              
241             An arrayref of allowed paths where wkhtmltopdf can find images and
242             other linked content. The temporary directory is added by default.
243             See wkhtmltopdf documentation for more information.
244              
245             =item disposition
246              
247             Default: I<inline>.
248              
249             The I<content-disposition> to set when sending the PDF file to the
250             client. Can be either I<inline> or (default) I<attachment>.
251              
252             =item filename
253              
254             Default: I<output.pdf>.
255              
256             The filename to send to the client.
257              
258             =item page_size
259              
260             Default: I<A4>.
261              
262             Page size option.
263             See wkhtmltopdf documentation for more information.
264              
265             =item orientation
266              
267             Default: I<portrait>.
268              
269             Orientation option.
270             See wkhtmltopdf documentation for more information.
271              
272             =back
273              
274             =head1 PARAMETERS
275              
276             Parameters are passed fvia the stash:
277              
278             $c->stash->{wkhtmltopdf} = {
279             html => $web_page,
280             };
281              
282             You can pass the following configuration options here, which will
283             override the global configuration: I<disposition>, I<filename>,
284             I<page_size>.
285              
286             Other options currently supported are:
287              
288             =over 4
289              
290             =item page-width, page-height
291              
292             Width and height of the page, overrides I<page_size>.
293              
294             =item margin-top, margin-right, margin-bottom, margin-left
295              
296             Margins, specified as I<3mm>, I<0.7in>, ...
297              
298             =back
299              
300             Have a look at I<wkhtmltopdf> documentation for more information
301             regarding these options.
302              
303             =head1 METHODS
304              
305             =over 4
306              
307             =item process()
308              
309             Generated the PDF as epr parameters in $c->stash->{wkhtmltopdf} or other
310             configured stash key. Calls C<render()> to perform actual rendering.
311             Output is stored in C<$c->response->body>.
312              
313             It is possible to forward to the process method of the view from inside
314             L<Catalyst>:
315              
316             $c->forward('View::Wkhtmltopdf');
317              
318             However, this is usually done automatically by L<Catalyst::Action::RenderView>.
319              
320             =item render($c, \%args)
321              
322             Generates a PDF from the arguments in I<\%args> and returns it.
323             Arguments are the same one would place in the stash key for
324             rendering + output via C<process()>, but the following are
325             (of course) ignored: I<disposition>, I<filename> (as they
326             only apply when outputting the content to the client).
327              
328             You can pass a I<template_args> key inside the arguments
329             hashref, which will be passed to L<Catalyst::View::TT>'s
330             C<render()> method. If not supplied, undef will be passed,
331             so the TT view method will behave as per its documentation.
332              
333             =back
334              
335             =head1 CHARACTER ENCODING
336              
337             At present time this library just uses UTF-8, which means it should
338             work in most circumstances. Patches are welcome for support of
339             different character sets.
340              
341             =head1 REQUIREMENTS
342              
343             I<wkhtmltopdf> command should be available on your system.
344              
345             =head1 TODO
346              
347             More configuration options (all the ones which I<wkhtmltopdf>
348             supports, likely) should be added. Also, we'll wanto to allow
349             to override them all at runtime.
350              
351             We might want to use pipes (L<IPC::Open2>) instead of relying
352             on temp files.
353              
354             And yes... we need to write tests!
355              
356             =head1 CONTRIBUTE
357              
358             Project in on GitHub:
359              
360             L<https://github.com/lordarthas/Catalyst-View-Wkhtmltopdf>
361              
362             =head1 AUTHOR
363              
364             Michele Beltrame E<lt>arthas@cpan.orgE<gt>
365              
366             =head1 CONTRIBUTORS
367              
368             jegade
369              
370             =head1 LICENSE
371              
372             This library is free software; you can redistribute it and/or modify
373             it under the same terms as Perl itself.
374              
375             =head1 SEE ALSO
376              
377             L<Catalyst>, L<Catalyst::View::TT>
378              
379             L<http://code.google.com/p/wkhtmltopdf/>
380              
381             =cut