App-Music-ChordPro
view release on metacpan or search on metacpan
lib/ChordPro/Output/PDF.pm view on Meta::CPAN
}
if ( $pagectrl->{compact_songs} ) {
$prefill = compact_songbook( $sb, $pagectrl );
return unless defined $prefill; # cancelled
}
progress( phase => "PDF",
index => 0,
total => scalar(@{$sb->{songs}}) );
$pr = (__PACKAGE__."::Writer")->new( $ps, $pdfapi );
warn("Generating PDF ", $options->{output} || "__new__.pdf", "...\n")
if $options->{verbose};
my $name = ::runtimeinfo("short");
$name =~ s/version.*/regression testing/ if $regtest;
my %info = ( Title => $options->{title} || $sb->{songs}->[0]->{meta}->{title}->[0],
Creator => $name );
while ( my ( $k, $v ) = each %{ $ps->{info} } ) {
next unless defined($v) && $v ne "";
next if $k eq "title" && $options->{title} && $k eq '%{title}';
$info{ucfirst($k)} = fmt_subst( $sb->{songs}->[0], $v );
}
$info{PageCtrl} = pagectrl_msg($pagectrl);
$pr->info(%info);
# The resultant songbook consists of 5 parts:
# 1, The cover. PDF doc or cho template.
# 2. The front matter. PDF doc or cho template.
# 3. The table of contents. May be templated.
# 4. The songs.
# 5. The back matter. PDF doc.
# All parts except the songs are optional.
my ( %start_of, %pages_of );
for ( qw( cover front toc songbook back ) ) {
$start_of{$_} = 1;
$pages_of{$_} = 0;
}
# The songbook...
my @book;
# Page number in the PDF (for now, later we'll prepend tocs etc.).
# Note that PDF page numbers start at 1.
my $page = 1;
# Logical page number offset.
my $page_offset = ( $options->{'start-page-number'} || 1 ) - 1;
$page_offset++ if $prefill && is_even($page_offset);
# if ( $pagectrl->{dual_pages} && is_odd($page_offset) ) {
# warn("Warning: Specifying an even start page when ".
# "pdf.odd-even-pages is in effect may yield surprising results.\n");
# }
# If there is back matter, and it has even pages, force
# alignment of the final song as well.
my $back_matter;
my $force_align;
if ( $pagectrl->{back_matter} ) {
$back_matter = $pdfapi->open( expand_tilde($pagectrl->{back_matter}) );
die("Missing back matter: ", $pagectrl->{back_matter}, "\n")
unless $back_matter;
$force_align =
!( is_even($page_offset) xor is_even($back_matter->pages))
if $pagectrl->{align_songs_extend};
}
for my $songindex ( 1 .. @{$sb->{songs}} ) {
my $song = $sb->{songs}->[$songindex-1];
local $pagectrl->{align_songs_spread} = $pagectrl->{align_songs_spread};
$pagectrl->{align_songs_spread} = 1 if is_odd($page_offset);
# Align.
if ( $song->{meta}->{pages} ) { # 2nd pass
if ( ( ($page+$page_offset) % 2)
&& $song->{meta}->{pages}
&& $song->{meta}->{pages} == 2 ) {
$pr->newpage($page+1);
$page++;
}
}
else {
$page += $pr->page_align( $pagectrl, "song$songindex", $page );
}
$song->{meta}->{tocpage} = $page; # physical
push( @book, [ $song->{meta}->{title}->[0], $song ] );
# Copy persistent assets into each of the songs.
if ( $sb->{assets} && %{$sb->{assets}} ) {
$song->{assets} //= {};
while ( my ($k,$v) = each %{$sb->{assets}} ) {
$song->{assets}->{$k} = $v;
}
}
return unless progress( msg => $song->{meta}->{title}->[0] );
$song->{meta}->{"chordpro.songsource"} //= $song->{source}->{file};
$pr->{bookmark} = "song_$songindex";
my $pages =
generate_song( $song,
{ pr => $pr,
page_idx => $page,
page_num => $page+$page_offset,
songindex => $songindex,
numsongs => scalar(@{$sb->{songs}}),
forcealign => $force_align,
pagectrl => $pagectrl,
} );
# Easy access to toc page.
$song->{meta}->{page} = $page+$page_offset;
if ( $song->{meta}->{bookmark} ) {
$pr->named_dest( $song->{meta}->{bookmark},
$pr->{pdf}->openpage($page)) if $pages;
}
else {
# Embedded PDF -> no toc.
lib/ChordPro/Output/PDF.pm view on Meta::CPAN
title => fmt_subst( $_->[-1], $tltpl ),
page => $p,
pageno => fmt_subst( $_->[-1], $pgtpl ),
} } @$book );
}
$frontmatter_songbook //= ChordPro::Songbook->new;
$frontmatter_songbook->add($_) for @songs;
$frontmatter_songbook->add($song);
}
# Prepend the front matter songs.
$force_align = $pagectrl->{align_songs_extend};
if ( $frontmatter_songbook && @{$frontmatter_songbook->{songs}} ) {
return unless progress( msg => "ToC" );
$page = 1;
my $toc = 0;
for ( @{$frontmatter_songbook->{songs}} ) {
# Localize song alignment settings.
local $pagectrl->{align_songs} =
$pagectrl->{align_tocs};
local $pagectrl->{align_songs_spread} =
$pagectrl->{align_tocs} eq "songs"
? $pagectrl->{align_songs_spread} : 0;
local $pagectrl->{align_songs_extend} =
$pagectrl->{align_tocs} eq "songs"
? $pagectrl->{align_songs_extend} : 0;
$toc++;
$pr->{bookmark} = "toc_$toc";
# warn("TOC $toc $page\n");
# use DDP; p $pagectrl, as => "for toc";
$page += $pr->page_align( $pagectrl, "toc$toc", $page );
# warn("TOC $toc $page\n");
my $pages =
generate_song( $_,
{ pr => $pr,
prepend => 1,
roman => 1,
page_idx => $page,
page_num => $page,
songindex => $toc,
numsongs => 0+@{$frontmatter_songbook->{songs}},
bookmark => $pr->{bookmark},
# forcealign => $force_align,
pagectrl => $pagectrl,
} );
$pr->named_dest( $_->{meta}->{bookmark},
$pr->{pdf}->openpage($page)) if $pages;
$page += $pages;
# warn("TOC $toc $page\n");
}
$pages_of{toc} = $page - 1;
$start_of{$_} += $page - 1 for qw( songbook back );
}
if ( $pagectrl->{front_matter} ) {
$page = 1;
my $matter = $pdfapi->open( expand_tilde($pagectrl->{front_matter}) );
die("Missing front matter: ", $pagectrl->{front_matter}, "\n") unless $matter;
return unless progress( msg => "Front matter" );
for ( 1 .. $matter->pages ) {
$pr->{pdf}->import_page( $matter, $_, $_ );
$page++;
}
$pages_of{front} = $matter->pages;
$start_of{$_} += $page - 1 for qw( toc songbook back );
}
# If we have a template, process it as a song and prepend.
my $covertpl;
if ( defined($options->{title}) && !@tocs ) {
my $tpl = "cover";
$covertpl = CP->findres( "$tpl.cho", class => "templates" );
if ( $verbose ) {
warn("Cover template",
$covertpl ? " found: $covertpl" : " not found: $tpl.cho\n")
}
}
if ( $covertpl ) {
my $page = 1;
my $opts = { fail => 'hard' };
my $lines = fs_load( $covertpl, $opts );
my $csb = ChordPro::Songbook->new;
$csb->parse_file( $lines, { %$opts,
generate => 'PDF' } );
for ( $csb->{songs}->[0] ) {
@{$_->{meta}}{ keys( %{$config->{meta}} ) } =
values ( %{$config->{meta}} );
$_->{meta}->{title} =
$options->{title} ?
[ $options->{title} ] : [ $_->{meta}->{title}->[0] ];
$_->{meta}->{subtitle} =
$options->{subtitle} ?
[ $options->{subtitle} ] : $_->{meta}->{subtitle};
}
for ( @{$csb->{songs}} ) {
my $p =
generate_song( $_,
{ pr => $pr,
prepend => 1,
roman => 1,
page_idx => $page,
page_num => $page,
songindex => 0,
numsongs => 1,
pagectrl => $pagectrl,
} );
$page += $p;
$start_of{$_} += $p for qw( songbook front toc back );
}
$pages_of{cover} = $page - 1;
}
elsif ( defined( $pagectrl->{cover} ) ) {
my $cover = $pdfapi->open( expand_tilde($pagectrl->{cover}) );
die("Missing cover: ", $pagectrl->{cover}, "\n") unless $cover;
$page = 0;
return unless progress( msg => "Cover" );
for ( 1 .. $cover->pages ) {
$page++;
$pr->{pdf}->import_page( $cover, $_, $page );
}
$pages_of{cover} = $page;
$start_of{$_} += $page for qw( songbook front toc back );
}
# Back matter (if any) has already been opened.
if ( $back_matter ) {
$page = $start_of{back};
return unless progress( msg => "Back matter" );
warn( "ASSERT: pages=", $pr->{pdf}->pages,
" back=", $start_of{back}, "\n" )
unless 1+$pr->{pdf}->pages == $start_of{back};
for ( 1 .. $back_matter->pages ) {
$pr->{pdf}->import_page( $back_matter, $_, $page );
$page++;
}
$pages_of{back} = $back_matter->pages;
}
if ( 0 and $::config->{debug}->{pages} & 0x01 ) {
warn("-- pre alignment\n");
for ( qw( cover front toc songbook back ) ) {
warn( sprintf("%4d %-10s %s\n",
$start_of{$_}, $_,
plural( sprintf("%4d",$pages_of{$_})," page") ));
}
warn("-- final\n");
}
# Alignment. Only if odd/even pages.
if ( $pagectrl->{dual_pages} ) {
my @parts = qw( front toc songbook back );
while ( @parts ) {
my $part = shift(@parts);
next unless $pages_of{$part};
# Always align parts, regardless of pagealign-songs.
local $pagectrl->{align_songs} = 1;
if ( @parts ) {
if ( $pr->page_align( $pagectrl,
$part,
$start_of{$part},
$part eq "songbook"
? $prefill
? 1
: is_odd($page_offset)
: 0 ) ) {
$start_of{$_}++ for $part, @parts;
}
}
else {
$start_of{$part} +=
$pr->page_align( $pagectrl, $part, $start_of{$part},
( run in 0.862 second using v1.01-cache-2.11-cpan-5b529ec07f3 )