Closed ohmycloud closed 3 years ago
@ohmycloud Quite right. That example doesn't work with the current PDF::Class and doesn't correctly build outlines.
I've changed sub dest(|c) { :destination($pdf.destination(|c)) }
to sub dest(|c) { :Dest($pdf.destination(|c)) }
in the README.
Please try that.
Thanks you! It worked.
Sorry for one more question, after I do some crop on the old pdf, and save the croped pdf, the outlines just doesn't move as expected when clicked. Did I make a mistake?
use v6;
use PDF::API6;
use PDF::Page;
use PDF::XObject;
use PDF::Content::Page :PageSizes;
use PDF::Destination :Fit;
for 1..$pages -> $n {
my PDF::Page $new-page = $pdf.add-page;
$new-page.bleed = 50mm;
my PDF::Page $page = $old-pdf.page($n);
$page.trim-box = Letter;
$page.bleed = 10mm;
my $gfx = $new-page.gfx;
# Import Page from the old PDF
my PDF::XObject $xo = $old-pdf.page($n).to-xobject;
# Add it to the new PDF's first page at 1/2 scale
my $width = $xo.width / 2;
my $bottom = 0;
my $left = 0;
$gfx.do($xo, $bottom, $left, :$width);
}
$pdf.outlines = $old-pdf.outlines; # clone outlines from old pdf
$pdf.save-as: "../tmp/pdf-crop.pdf";
@ohmycloud, Cloning of outlines isn't enough. They're tightly bound by direct references to the pages. On top of that they specify the absolute position on the output page, which needs to be recalculated. PDF::API6 doesn't have any support for this yet.
I've coded minimal changes using PDF::Class that copies the outlines from the input to the output PDF and uses FitWindow so that it navigates to the page, but not the position on the page, just to side-step all the calculations involved.
use v6;
use PDF::API6;
use PDF::Page;
use PDF::XObject;
use PDF::Content::Page :PageSizes;
use PDF::Destination :Fit;
use PDF::Catalog;
use PDF::Action::GoTo;
sub postfix:<mm>(Numeric $v){ ($v * 2.83).round(1) };
my PDF::API6 $old-pdf .= open: "../tmp/make-toc.pdf";
my PDF::API6 $pdf .= new;
my UInt $pages = $old-pdf.page-count;
sub dest(|c) { :Dest($pdf.destination(|c)) }
# mapping of input pages to output page numbers
my UInt %page-numbers{PDF::Page};
for 1..$pages -> $n {
my PDF::Page $new-page = $pdf.add-page;
$new-page.bleed = 50mm;
my PDF::Page $page = $old-pdf.page($n);
%page-numbers{$page} = $n;
$page.trim-box = Letter;
$page.bleed = 10mm;
my $gfx = $new-page.gfx;
# Import Page from the old PDF
my PDF::XObject $xo = $old-pdf.page($n).to-xobject;
# Add it to the new PDF's first page at 1/2 scale
my $width = $xo.width / 2;
my $bottom = 20mm;
my $left = 10mm;
$gfx.do($xo, $bottom, $left, :$width);
}
my @outlines = copy-outlines($old-pdf.outlines);
$pdf.outlines.kids = @outlines;
$pdf.save-as: "../tmp/pdf-crop.pdf";
sub copy-outlines($outlines) {
$outlines.kids.map: {
my %out = :Title(.Title), ;
with .Dest // .A {
my UInt $page = page-number($_);
%out ,= dest(:$page, :fit(FitWindow));
}
%out<kids> = copy-outlines($_);
%out;
}
}
# copy outlines when there is a 1-1 correspondance between input and output pages
subset DestInternalRef of Hash where PDF::Action::GoTo | PDF::Catalog::DestDict;
multi sub page-number(DestInternalRef $ref) {
page-number($ref.D);
}
multi sub page-number(PDF::Page $page) {
%page-numbers{$page};
}
multi sub page-number(PDF::Destination $_) {
page-number(.page);
}
Possibly PDF::API6 should have better support for importing Outlines, Annotations etc, or there should be a dedicated module for importing Pages and other related resources.
Thank you so much! It works.
I use the follwing code to make outlines, it works quit fine. But when I opened the output pdf file, and click the outlines on the left, I expect it will jump to the specified page number, but nothing happend.