App-Music-ChordPro
view release on metacpan or search on metacpan
lib/ChordPro/lib/SVGPDF.pm view on Meta::CPAN
#! perl
use v5.26;
use Object::Pad;
use Carp;
use utf8;
class SVGPDF;
our $VERSION = '0.092';
=head1 NAME
SVGPDF - Create PDF XObject from SVG data
=head1 SYNOPSIS
my $pdf = PDF::API2->new;
my $svg = SVGPDF->new($pdf);
my $xof = $svg->process("demo.svg");
# If all goes well, $xof is an array of hashes, each representing an
# XObject corresponding to the <svg> elements in the file.
# Get a page and graphics context.
my $page = $pdf->page;
$page->bbox( 0, 0, 595, 842 );
my $gfx = $pdf->gfx;
# Place the objects.
my $y = 832;
foreach my $xo ( @$xof ) {
my @bb = @{$xo->{vbox}};
my $h = $bb[3];
$gfx->object( $xo->{xo}, 10, $y-$h, 1 );
$y -= $h;
}
$pdf->save("demo.pdf");
=head1 DESCRIPTION
This module processes SVG data and produces one or more PDF XObjects
to be placed in a PDF document. This module is intended to be used
with L<PDF::Builder>, L<PDF::API2> and compatible PDF packages.
The main method is process(). It takes the SVG from an input source, see
L</INPUT>.
=head1 COORDINATES & UNITS
SVG coordinates run from top-left to bottom-right.
Dimensions without units are B<pixels>, at 96 pixels / inch. E.g.,
C<width="96"> means 96px (pixels) and is equal to 72pt (points) or 1in (inch).
For font sizes, CSS defines C<em> to be equal to the font size, and
C<ex> is half of the font size.
=head1 CONSTRUCTORS
=head2 SVGPDF->new($pdf)
In its most simple form, a new SVGPDF object can be created with a
single argument, the PDF document.
There are a few optional arguments, these can be specified as
key/value pairs.
=over 8
=item C<fc>
A reference to a callback routine to handle fonts.
See L</FONT HANDLER CALLBACK>.
It may also be an array of routines which will be called in
sequence until one of them succeeds (returns a 'true' result).
=item C<fontsize>
The font size to be used for dimensions in 'ex' and 'em' units.
Note that CSS defines 'em' to be the font size, and 'ex' half of the
font size.
=item C<pagesize>
An array reference containing the maximum width and height of the
resultant image.
There is no widely accepted default for this, so we use C<[595,842]>
which corresponds to an ISO A4 page.
=item C<grid>
If not zero, a grid will be added to the image. This is mostly for
developing and debugging.
The value determines the grid spacing.
=item C<verbose>
Verbosity of informational messages. Set to zero to silence all but
fatal errors.
=item C<debug>
lib/ChordPro/lib/SVGPDF.pm view on Meta::CPAN
use SVGPDF::Rect;
use SVGPDF::Style;
use SVGPDF::Svg;
use SVGPDF::Text;
use SVGPDF::Tspan;
use SVGPDF::Use;
################ General methods ################
=head1 METHODS
=cut
# $pdf [ , fc => $callback ] [, atts => { ... } ] [, foo => bar ]
# pdf => $pdf [ , fc => $callback ] [, atts => { ... } ] [, foo => bar ]
sub BUILDARGS ( @args ) {
my $cls = shift(@args);
# Assume first is pdf if uneven.
unshift( @args, "pdf" ) if @args % 2;
my %args = @args;
@args = ();
push( @args, $_, delete $args{$_} ) for qw( pdf fc tc );
# Flatten everything else into %atts.
my %x = %{ delete($args{atts}) // {} };
$x{$_} = $args{$_} for keys(%args);
# And store as ref.
push( @args, "atts", \%x );
# Return new argument list.
@args;
}
BUILD {
$debug = $atts->{debug} || 0;
$verbose = $atts->{verbose} // $debug;
$grid = $atts->{grid} || 0;
$prog = $atts->{prog} || 0;
$debug_styles = $atts->{debug_styles} || $debug > 1;
$trace = $atts->{trace} || 0;
$pagesize = $atts->{pagesize} || [ 595, 842 ];
$fontsize = $atts->{fontsize} || 12;
$wstokens = $atts->{wstokens} || 0;
$indent = "";
$xoforms = [];
$defs = {};
$fontmanager = SVGPDF::FontManager->new( svg => $self );
$self;
}
=head2 process
$xof = $svg->process( $data, %options )
This methods gets SVG data from C<$data> and returns an array reference
with rendered images. See L</OUTPUT> for details.
The input is read using File::LoadLines. See L</INPUT> for details.
Recognized attributes in C<%options> are:
=over 4
=item fontsize
The font size to be used for dimensions in 'ex' and 'em' units.
This value overrides the value set in the constructor.
=item combine
An SVG can produce multiple XObjects, but sometimes these should be
kept as a single image.
There are two ways to combine the image objects. This can be selected
by setting $opts{combine} to either C<"stacked"> or C<"bbox">.
Type C<"stacked"> (default) stacks the images on top of each other,
left sides aligned. The bounding box of each object is only used to
obtain the width and height.
Type C<"bbox"> stacks the images using the bounding box details. The
origins of the images are vertically aligned and images may protrude
other images when the image extends below the origin.
=item sep
When combining images, add additional vertical space between the
individual images.
=back
=cut
method process ( $data, %options ) {
if ( $options{reset} ) { # for testing, mostly
$xoforms = [];
}
my $save_fontsize = $fontsize;
$fontsize = $options{fontsize} if $options{fontsize};
# TODO: Page size
# Load the SVG data.
my $svg = SVGPDF::Parser->new;
my $tree = $svg->parse_file
( $data,
whitespace_tokens => $wstokens||$options{whitespace_tokens} );
return unless $tree;
# CSS persists over svgs, but not over files.
$css = SVGPDF::CSS->new;
# Search for svg elements and process them.
$self->search($tree);
# Restore.
lib/ChordPro/lib/SVGPDF.pm view on Meta::CPAN
$xo->fill;
$xo->rectangle( $bb[2]-$dd, $bb[3]-$dd, $bb[2]+$dd, $bb[3]+$dd);
$xo->fill_color("magenta");
$xo->fill;
# Show origin. This will cover the bb corner unless it is offset.
$xo->rectangle( -$dd, $dd, $dd, -$dd );
$xo->fill_color("red");
$xo->fill;
$xo->stroke_color("#bbbbbb");
# Draw the grid (thick lines).
$xo->line_width($thick);
for ( my $x = 0; $x <= $bb[2]; $x += 5*$d ) {
$xo->move( $x, $bb[1] );
$xo->vline($bb[3]);
$xo->stroke;
}
for ( my $x = -5*$d; $x > $bb[0]; $x -= 5*$d ) {
next;
$xo->move( $x, $bb[1] );
$xo->vline($bb[3]);
$xo->stroke;
}
for ( my $y = 0; $y <= $bb[3]; $y += 5*$d ) {
$xo->move( $bb[0], $y );
$xo->hline($bb[2]);
$xo->stroke;
}
for ( my $y = -5*$d; $y > $bb[0]; $y -= 5*$d ) {
next;
$xo->move( $bb[0], $y );
$xo->hline($bb[2]);
$xo->stroke;
}
# Draw the grid (thin lines).
$xo->line_width($thin);
for ( my $x = 0; $x <= $w; $x += $d ) {
$xo->move( $x, $bb[1] );
$xo->vline($bb[3]);
$xo->stroke;
}
for ( my $x = -$d; $x > $bb[0]; $x -= $d ) {
$xo->move( $x, $bb[1] );
$xo->vline($bb[3]);
$xo->stroke;
}
for ( my $y = 0; $y <= $h; $y += $d ) {
$xo->move( $bb[0], $y );
$xo->hline($bb[2]);
$xo->stroke;
}
for ( my $y = -$d; $y > $bb[1]; $y -= $d ) {
$xo->move( $bb[0], $y );
$xo->hline($bb[2]);
$xo->stroke;
}
$xo->restore;
}
=head1 INPUT
The input SVG data B<must> be correct XML data.
The data can be a single C<< <svg> >> element, or a container
element (e.g. C<< <html> >> or C<< <xml> >>) with one or more
C<< <svg> >> elements among its children.
The SVG data can come from several sources:
=over 4
=item *
An SVG document on disk, specified as the name of the document.
=item *
A file handle, opened on a SVG document, specified as a glob
reference. You can use C<\*DATA> to append the SVG data after a
C<__DATA__> separator at the end of the program.
=item *
A string containing SVG data, specified as a reference to a scalar.
=back
The input is read using L<File::LoadLines>. See its documentation for
details.
=head1 OUTPUT
The result from calling process() is a reference to an array
containing hashes that describe the XObjects. Each hash has the
following keys:
=over 8
=item C<vbox>
The viewBox as specified in the SVG element.
If no viewBox is specified it is set to C<0 0> I<W H>, where I<W> and
I<H> are the width and the height.
=item C<bbox>
Same as the C<vbox>, but using bottom-left and top-right coordinates.
=item C<width>
The width of the XObject, as specified in the SVG element or derived
from its viewBox.
=item C<height>
The height of the XObject, as specified in the SVG element or derived
from its viewBox.
=item C<vwidth>
The desired width, as specified in the SVG element or derived
from its viewBox.
=item C<vheight>
The desired height, as specified in the SVG element or derived
from its viewBox.
=item C<xo>
The XObject itself.
=back
=head1 FONT HANDLER CALLBACK
In SVG fonts are designated by style attributes C<font-family>,
C<font-style>, C<font-weight>, and C<font-size>. How these translate
to a PDF font is system dependent. SVGPDF provides a callback
mechanism to handle this. As described at L<CONSTRUCTOR>, constructor
argument C<fc> can be set to designate a user routine.
When a font is required at the PDF level, SVGPDF first checks if a
C<@font-face> CSS rule has been set up with matching properties. If a
match is found, it is resolved and the font is set. If there is no
appropriate CSS rule for this font, the callback is called with the
following arguments:
( $self, %args )
( run in 1.628 second using v1.01-cache-2.11-cpan-98e64b0badf )