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 )