Как сделать так, чтобы флажки отображались в PDF с помощью Perl's PDF :: API2 - PullRequest
1 голос
/ 25 июня 2019

Я несколько дней пытался получить CheckBox или Radio Button для рендеринга с использованием PDF :: API2, но не смог.

Я поливал справочник PDFMark, спецификацию PDF,и любые примеры, которые я смог найти.Я могу получить простые аннотации Widget для рендеринга, но не смог получить ничего, что требует корректной работы потока внешнего вида или словаря внешнего вида.Ниже приведен выбор тестового кода, пытающегося установить флажок:

#!/usr/bin/perl

use PDF::API2;
use PDF::API2::Basic::PDF::Utils;

# set up pdf
my $pdfOptions = {};
my $pdf = PDF::API2->new( \$pdfOptions );
my $page = $pdf->page();

$page->mediabox( 'Letter' );

my $AcroForm = PDFDict();
$AcroForm->{NeedAppearances} = PDFBool( 'true' );
$AcroForm->realise;

my @Annots;
my @Fields;

my $resourceObj = PDFDict();
$resourceObj->{Type}     = PDFName( 'Font' );
$resourceObj->{Subtype}  = PDFName( 'Type1' );
$resourceObj->{Name}     = PDFName( 'ZaDb' );
$resourceObj->{BaseFont} = PDFName( 'ZapfDingbats' );
$resourceObj->realise();


$AcroForm->{DR} = PDFDict();
$AcroForm->{DR}->{Font} = PDFDict();
$AcroForm->{DR}->{ZaDb} = $resourceObj;
$AcroForm->realise();

my $item = PDFDict();

$item->{P}   = $page;
$item->{Type}    = PDFName( 'Annot' );
$item->{Subtype} = PDFName( 'Widget' );
$item->{FT}  = PDFName( 'Btn' );

my $yes = PDFName( 'Yes' );
my $off = PDFName( 'Off' );

$item->{P}   = $page;
$item->{Type}    = PDFName( 'Annot' );
$item->{Subtype} = PDFName( 'Widget' );
$item->{Rect}    = PDF::API2::Basic::PDF::Literal->new( "[100 300 200 400]" );
$item->{FT}  = PDFName( 'Btn' );
$item->{T}   = PDFStr( 'Urgent' );
$item->{V}   = PDFName( 'Yes' );
$item->{AS}  = PDFName( 'Yes' );
$item->{AP}  = PDFDict();
$item->{AP}->{N} = PDFDict();

# My understanding is that these would be nulled to be used with NeedAppearances
$item->{AP}->{N}->{$yes} = PDFNull(); 
$item->{AP}->{N}->{$off} = PDFNull();

$item->realise();

push @Annots, $item;
push @Fields, $item if( $AcroForm );

$page->{Annots} = PDFArray( @Annots );
$AcroForm->{Fields} = PDFArray(@Fields) if( $AcroForm );
$pdf->{Root}->{AcroForm} = $AcroForm if( $AcroForm );

print $pdf->stringify();
exit;

Я бы ожидал увидеть флажок в середине этой страницы, вместо этого я получил пустую неиспользуемую аннотацию.Я пытаюсь заставить флаг NeedAppearances работать, поскольку я перестал пытаться создать правильный словарь потока / внешнего вида, но был бы благодарен за решения, использующие любой из этих методов.

1 Ответ

1 голос
/ 27 июня 2019

Это код, который я наконец-то правильно отобразил, как в браузере, так и в Adobe Reader. Публикуем это потому, что рабочие примеры использования этого модуля для аннотаций виджетов редки.

Хитрость заключалась в следующем: использование {pdf} -> new_obj для определения объектов и захвата их ссылок, а также правильного размещения AcroForm и, наконец, установка свойства {'stream'} для пустой строки, что, я полагаю, принудительно отображал теги stream / endstream, позволяя читателям PDF привязываться к потокам внешнего вида.

Я использовал qpdf для анализа вывода, что позволило мне увидеть, как различные методы модуля влияют на окончательный вывод PDF.

    #!/usr/bin/perl

    # set up pdf
    my $pdfOptions = {};
    my $pdf = PDF::API2->new( \$pdfOptions );
    my $page = $pdf->page();

    $page->mediabox( 'Letter' );

    my @Annots;
    my @Fields;

    my $fontObj = PDFDict();
    $fontObj->realise();
    $fontObj->{Type} = PDFName( 'Font' );
    $fontObj->{Subtype} = PDFName( 'Type1' );
    $fontObj->{BaseFont} = PDFName( 'Times-Roman' );
    $fontObj = $pdf->{pdf}->new_obj( $fontObj );

    my $resourceObj = PDFDict();
    $resourceObj->realise();

    $resourceObj->{Font} = PDFDict();
    $resourceObj->{Font}->realise();

    $resourceObj->{Font}->{F1} = $fontObj;
    $resourceObj = $pdf->{pdf}->new_obj( $resourceObj );

    my $AcroForm = PDFDict();
    $AcroForm->realise();
    $AcroForm->{DR} = $resourceObj;
    $AcroForm->{NeedAppearances} = PDFBool( 'true' );

    my $yesObj = PDF::API2::Resource::XObject::Form->new( $pdf );
    $yesObj->{Resources} = $resourceObj;
    $yesObj->{BBox} = PDF::API2::Basic::PDF::Literal->new( "[100 300 200 400]" );
    $yesObj->realise();
    $yesObj->{' stream'} = '';
    $yesObj = $pdf->{pdf}->new_obj( $yesObj );

    my $noObj = PDF::API2::Resource::XObject::Form->new( $pdf );
    $noObj->{Resources} = $resourceObj;
    $noObj->{Subtype} = PDFName( 'Form' );
    $noObj->{BBox} = PDF::API2::Basic::PDF::Literal->new( "[100 300 200 400]" );
    $noObj->realise();
    $noObj->{' stream'} = '';
    $noObj = $pdf->{pdf}->new_obj( $noObj );

    my $item = PDFDict();
    $item->{Type}    = PDFName( 'Annot' );
    $item->{Subtype} = PDFName( 'Widget' );
    $item->{FT}      = PDFName( 'Btn' );
    $item->{T}       = PDFStr( 'checkbox1' );
    $item->{V}       = PDFName( 'Yes' );
    $item->{P}       = $page;
    $item->{Rect}    = PDF::API2::Basic::PDF::Literal->new( "[100 300 200 400]" );
    $item->{H}       = PDFName( 'N' );
    $item->{AS} = PDFName('Yes');

    $item->{AP}      = PDFDict();
    $item->{AP}->realise();

    $item->{AP}->{N} = PDFDict();
    $item->{AP}->{N}->realise();
    $item->{AP}->{N}->{'Yes'} = $yesObj;
    $item->{AP}->{N}->{'Off'} = $noObj;

    $item = $pdf->{pdf}->new_obj( $item );

    $item->realise();

    push @Annots, $item;
    push @Fields, $item if( $AcroForm );

    $page->{Annots} = PDFArray( @Annots );
    $AcroForm->{Fields} = PDFArray(@Fields) if( $AcroForm );
    $pdf->{catalog}->{'AcroForm'} = $AcroForm;
    $pdf->{pdf}->out_obj($pdf->{catalog});

    print $pdf->stringify();
    exit;
...