Это код, который я наконец-то правильно отобразил, как в браузере, так и в 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;