=pod

=for vim
   vim: tw=72 ts=3 sts=3 sw=3 et ai :

=encoding utf8

=head1 NAME

PDF::Collage - PDF manipulation with scissors and glue


=head1 VERSION

This document describes PDF::Collage version 0.001001.

=begin html

<a href="https://travis-ci.org/polettix/PDF-Collage">
<img alt="Build Status" src="https://travis-ci.org/polettix/PDF-Collage.svg?branch=master">
</a>
<a href="https://www.perl.org/">
<img alt="Perl Version" src="https://img.shields.io/badge/perl-5.24+-brightgreen.svg">
</a>
<a href="https://badge.fury.io/pl/PDF-Collage">
<img alt="Current CPAN version" src="https://badge.fury.io/pl/PDF-Collage.svg">
</a>
<a href="http://cpants.cpanauthors.org/dist/PDF-Collage">
<img alt="Kwalitee" src="http://cpants.cpanauthors.org/dist/PDF-Collage.png">
</a>
<a href="http://www.cpantesters.org/distro/O/PDF-Collage.html?distmat=1">
<img alt="CPAN Testers" src="https://img.shields.io/badge/cpan-testers-blue.svg">
</a>
<a href="http://matrix.cpantesters.org/?dist=PDF-Collage">
<img alt="CPAN Testers Matrix" src="https://img.shields.io/badge/matrix-@testers-blue.svg">
</a>

=end html

=head1 SYNOPSIS

   use PDF::Collage qw< collage >;

   # $input might be... many things
   my $collage = collage($input);
   my $pdf = $collage->render(\%data);
   $pdf->saveas('/path/to/somefile.pdf');


=head1 DESCRIPTION

C<PDF::Collage> helps generate an object wrapping either a
L<PDF::Collage::Template> or a L<PDF::Collage::TemplatesCollection>
(collectively referred as I<renderable object>).

These allow eventually generate L<PDF::Builder> objects, after applying
the supported transformations; this allows the generated PDF to be saved
(e.g. using the C<saveas> method of the L<PDF::Builder> object).

The I<Do What I Mean> interface L</collage> is a one-stop-shop for
getting one such object; it accepts a variety of inputs, including TAR
bundles (or their directory counterparts).

This distribution supports two basic types of inputs:

=over

=item *

I<definition> representing single templates, allowing the instantiation
of a L<PDF::Collage::Template> object;

=item *

I<anything> that can be turned into a L<Data::Resolver> object, leading
to a L<PDF::Collage::TemplatesCollection> (which, in turn, manages a
collection of L<PDF::Collage::Template> objects).

=back

=head2 Single Template Example

The details about the format for single templates can be found in the
documentation for L<PDF::Collage::Template>.

The following is an example of a possible sequence of commands, which
take page 5 from a pre-existing PDF file available in the filesystem and
put some text over it in selected positions.

   [  # a template is basically a sequence of commands in an array

      {  # set defaults for other commands
         op => 'set-defaults',
         font => 'DejaVuSans.ttf',
         'font-size' => 12,
         level => 'INFO',
      },

      {
         op => 'log',
         message => 'starting operations...',
         level   => 'WARN', # override defaults
      },

      {  # add-page by defaults appends to the end
         op => 'add-page',
         from => 'existing-file.pdf', # relative to current dir
         'from-page' => 5,
      },

      {
         op => 'add-text',
         x => 10,
         y => 20,
         text => 'this is verbatim text',
      },

      {  # text-template, rendered via Template::Perlish
         op => 'add-text',
         x => 10,
         y => 40,
         'text-template' => '[% foo %] is [% bar.baz %]',
      },

      {  # text-variable, rendered via Template::Perlish
         op => 'add-text',
         x => 10,
         y => 60,
         'text-variable' => 'bar.baz',
      },

      {
         op => 'add-image',
         path => 'logo.png',   # relative to current dir
         x => 10,
         y => 150,
         width => 50,
         height => 50,
      },

      {
         op => 'log',
         message => 'that's all folks!',
      },
   ]

The template can refer anything in the filesystem, hence it's up to the
user to make sure that the elements are properly available in the
specific paths (in the example above, it would be the PDF file
C<existing-file.pdf> and the image file C<logo.png>, both assumed to be
in the current directory).

Refer to L</Templates Collection> for something more I<cohesive>.

=head2 Templates Collection

A templates collection is... a collection of templates. It allows
carrying around multiple templates at once, as well as artifacts that
are deemed important to have around, e.g. because they are referred from
the commands. As such, a collection might I<technically> contain a
single template.

A collection always needs a L<Data::Resolver>-compatible function to
work properly. Details are in the documentation for
L<PDF::Collage::TemplatesCollection>, here's an example of the
I<structure> of the keys that it should support:

   definitions/bar.json
   definitions/foo.json
   definitions/galook.json
   existing-file.pdf
   logo.png

Every key ending with C<.json> and starting with C<definitions/>,
optionally prefixed with C<./> (to cope with possible variations in TAR
archives) is considered a file containing the instructions valid for a
single template.

The name part (in the example C<bar>, C<foo>, and C<galook>) is the
I<selector>, which can be used to retrieve that specific sequence of
commands from the collection via
L<PDF::Collage::TemplatesCollection/get>, getting back a
L<PDF::Collage::Template> object.

To retrieve elements from the resolver, e.g. to get a page from the
C<existing-file.pdf> or the image C<logo.png>, it's possible to use two
functions that are injected in the L<Template::Perlish> namespace,
namely C<as_data> and C<as_file>, depending on the needs. The following
fragment is a command for taking page 5 from the document accessible
through the resolver and the image too:

      {
         op => 'add-page',
         'from-page' => 5,
         from => '[%= as_file("existing-file.pdf") %]',
      },

      {
         op => 'add-image',
         path => '[%= as_file("logo.png") %]',
         x => 10,
         y => 150,
         width => 50,
         height => 50,
      },

Note that it's necessary to open the template part with C<[%=> to get
the filename back into the data.

By default, the injected function C<as_file> will try to keep the
I<extension>, derived from the provided key assuming it's a
filename-like string. Everything after the first dot is kept. It's
possible to disable this renaming (if and when it occurs) by passing a
second parameter with a false value, like in C<as_file($key, 0)>.

=head1 INTERFACE

This module has a I<function-oriented> interface.

=head2 B<< collage >>

   my $pc = collage($input);
   my $pc = collage(auto => $input);      # same as above
   my $pc = collage(resolver => $data_resolver_instance); # Data::Resolver
   my $pc = collage(dir => $path_to_dir);
   my $pc = collage(tar => $path_to_tar);
   my $pc = collage(definition => \%hash_definition);
   my $pc = collage(definition => \@array_definition);
   my $pc = collage(definition => $json_hash_or_array);

This is a I<Do What I Mean> catchall function to generate an instance of
either L<PDF::Collage::Template> or
L<PDF::Collage::TemplatesCollection>.

The function acts as a dispatcher to one of the other functions:
L</collage_from_definition>, L</collage_from_dir>,
L</collage_from_resolver>, and L</collage_from_tar>.

=head2 B<< collage_from_definition >>

   my $pc = collage_from_definition($definition);

Generate a renderable object from a C<$definition>.

If the definition is a string starting with either C<{> or C<[>, it is
considered a valid JSON string and decoded as such, then processed as
follows.

If the definition is an array reference, it is turned into an hash
reference with a single key C<commands>, associated to the array
reference as value.

If the definition is an hash reference, it is considered a suitable
input for instantiating an object from L<PDF::Collage::Template>, which
is returned back.

=head2 B<< collage_from_dir >>

   my $pc = collage_from_dir($path, %other_args);

This function is a thin wrapper around L</collage_from_resolver>; it
first instantiates a L<Data::Resolver> object of factory type
C<resolver_from_dir>, using the provided C<$path> and C<%other_args>,
then passes the resulting object to L</collage_from_resolver>.

=head2 B<< collage_from_resolver >>

   my $pc = collage_from_resolver($resolver);

Instantiate a L<PDF::Collage::TemplatesCollection> object passing
C<$resolver> as the value associated to key C<resolver>.

=head2 B<< collage_from_tar >>

   my $pc = collage_from_tar($path, %other_args);

This function is a thin wrapper around L</collage_from_resolver>; it
first instantiates a L<Data::Resolver> object of factory type
C<resolver_from_tar>, using the provided C<$path> and C<%other_args>,
then passes the resulting object to L</collage_from_resolver>.


=head1 BUGS AND LIMITATIONS

Minimum perl version 5.24.

Report bugs through GitHub (patches welcome) at
L<https://github.com/polettix/PDF-Collage>.

=head1 AUTHOR

Flavio Poletti <flavio@polettix.it>

=head1 COPYRIGHT AND LICENSE

Copyright 2023 by Flavio Poletti <flavio@polettix.it>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


=cut
