11

PDFBoxでPDFフォームを「平坦化」(フォームフィールドを削除してフィールドのテキストを保持)するにはどうすればよいですか?

同じ質問がここで答えられました:

これを行う簡単な方法は、acrofrom からフィールドを削除することです。

このためには、ドキュメント カタログを取得してから acroform を取得し、この acroform からすべてのフィールドを削除するだけです。

グラフィック表示は注釈とリンクされ、ドキュメント内にとどまります。

だから私はこのコードを書いた:

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDField;

public class PdfBoxTest {
    public void test() throws Exception {
        PDDocument pdDoc = PDDocument.load(new File("E:\\Form-Test.pdf"));
        PDDocumentCatalog pdCatalog = pdDoc.getDocumentCatalog();
        PDAcroForm acroForm = pdCatalog.getAcroForm();

        if (acroForm == null) {
            System.out.println("No form-field --> stop");
            return;
        }

        @SuppressWarnings("unchecked")
        List<PDField> fields = acroForm.getFields();

        // set the text in the form-field <-- does work
        for (PDField field : fields) {
            if (field.getFullyQualifiedName().equals("formfield1")) {
                field.setValue("Test-String");
            }
        }

        // remove form-field but keep text ???
        // acroForm.getFields().clear();         <-- does not work
        // acroForm.setFields(null);             <-- does not work
        // acroForm.setFields(new ArrayList());  <-- does not work
        // ???

        pdDoc.save("E:\\Form-Test-Result.pdf");
        pdDoc.close();
    }
}
4

11 に答える 11

7

以下に示すように、setReadOnlyが機能しました-

   @SuppressWarnings("unchecked")
    List<PDField> fields = acroForm.getFields();
    for (PDField field : fields) {
        if (field.getFullyQualifiedName().equals("formfield1")) {
            field.setReadOnly(true);
        }
    }
于 2013-07-18T15:11:19.277 に答える
6

PDFリファレンスガイドについて読んだ後、値1の「Ff」キー(フィールドフラグ)を追加することで、AcroFormフィールドの読み取り専用モードを非常に簡単に設定できることを発見しました。

設定されている場合、ユーザーはフィールドの値を変更できません。関連するウィジェットの注釈は、ユーザーと対話しません。つまり、マウス クリックに応答したり、マウスの動きに応じて外観を変更したりしません。このフラグは、値がデータベースから計算またはインポートされるフィールドに役立ちます。

コードは次のようになります(pdfbox libを使用):

 public static void makeAllWidgetsReadOnly(PDDocument pdDoc) throws IOException {

    PDDocumentCatalog catalog = pdDoc.getDocumentCatalog();

    PDAcroForm form = catalog.getAcroForm();

    List<PDField> acroFormFields = form.getFields();

    System.out.println(String.format("found %d acroFrom fields", acroFormFields.size()));

    for(PDField field: acroFormFields) {
        makeAcroFieldReadOnly(field);
    }
}

private static void makeAcroFieldReadOnly(PDField field) {

    field.getDictionary().setInt("Ff",1);

}
于 2015-01-23T17:37:37.537 に答える
4

acroform を平坦化し、pdfBox を使用してフォーム フィールドの値を保持するソリューション:

pdfbox 2.0.1で私のために働いた解決策:

File myFile = new File("myFile.pdf");
PDDocument pdDoc = PDDocument.load(myFile);
PDDocumentCatalog pdCatalog = pdDoc.getDocumentCatalog();
PDAcroForm pdAcroForm = pdCatalog.getAcroForm();

// set the NeedAppearances flag to false
pdAcroForm.setNeedAppearances(false);


field.setValue("new-value");

pdAcroForm.flatten();
pdDoc.save("myFlattenedFile.pdf");
pdDoc.close();

上記のソリューション リンクの 2 つの追加手順を実行する必要はありませんでした。

// correct the missing page link for the annotations
// Add the missing resources to the form

OpenOffice 4.1.1 で PDF フォームを作成し、PDF にエクスポートしました。OpenOffice エクスポート ダイアログで選択された 2 つの項目は次のとおりです。

  1. 「PDFフォームの作成」を選択
  2. 「PDF」形式で送信 - 「FDF」を選択した場合よりも PDF ファイルのサイズが小さくなりますが、PDF フォームとして動作することがわかりました。

PdfBox を使用してフォーム フィールドにデータを入力し、フォーム フィールドを削除してフォーム フィールドの値を保持するフラット化された pdf ファイルを作成しました。

于 2016-05-15T19:04:51.117 に答える
2

実際に acrobat フォーム フィールドを「平坦化」するには、一見しただけでなく、やるべきことがたくさんあるようです。PDF標準を調べた後、3つのステップで実際の平坦化を達成することができました:

  1. フィールド値を保存
  2. ウィジェットを削除
  3. フォームフィールドを削除

3つの手順はすべてpdfboxで実行できます(私は1.8.5を使用しました)。以下に、私がそれをどのように行ったかをスケッチします。何が起こっているのかを理解するための非常に役立つツールは、PDF Debuggerです。

フィールドを保存する

これは、3 つのステップの中で最も複雑なステップです。

フィールドの値を保存するには、フィールドのウィジェットごとに、そのコンテンツを pdf のコンテンツに保存する必要があります。これを行う最も簡単な方法は、各ウィジェットの外観をウィジェットのページに描画することです。

void saveFieldValue( PDField field ) throws IOException
{
    PDDocument document = getDocument( field );
    // see PDField.getWidget()
    for( PDAnnotationWidget widget : getWidgets( field ) )
    {
        PDPage parentPage = getPage( widget );

        try (PDPageContentStream contentStream = new PDPageContentStream( document, parentPage, true, true ))
        {
            writeContent( contentStream, widget );
        }
    }
}

void writeContent( PDPageContentStream contentStream, PDAnnotationWidget widget )
        throws IOException
{
    PDAppearanceStream appearanceStream = getAppearanceStream( widget );
    PDXObject xobject = new PDXObjectForm( appearanceStream.getStream() );
    AffineTransform transformation = getPositioningTransformation( widget.getRectangle() );

    contentStream.drawXObject( xobject, transformation );
}

外観は、ウィジェットのすべてのコンテンツ (値、フォント、サイズ、回転など) を含む XObject ストリームです。ウィジェットの長方形から抽出できるページ上の正しい位置に配置するだけです。

ウィジェットを削除する

上記のように、各フィールドには複数のウィジェットを含めることができます。ウィジェットは、フォーム フィールドを編集する方法、トリガーする方法、編集していないときに表示する方法などを処理します。

削除するには、ページの注釈から削除する必要があります。

void removeWidget( PDAnnotationWidget widget ) throws IOException
{
    PDPage widgetPage = getPage( widget );
    List<PDAnnotation> annotations = widgetPage.getAnnotations();
    PDAnnotation deleteCandidate = getMatchingCOSObjectable( annotations, widget );
    if( deleteCandidate != null && annotations.remove( deleteCandidate ) )
        widgetPage.setAnnotations( annotations );
}

PDAnnotationWidget は一種のラッパーであるため、注釈には正確な PDAnnotationWidget が含まれていない場合があることに注意してください。一致する COSObject を持つものを削除する必要があります。

フォームフィールドを削除

最後のステップとして、フォーム フィールド自体を削除します。これは、上記の他の投稿と大差ありません。

void removeFormfield( PDField field ) throws IOException
{
    PDAcroForm acroForm = field.getAcroForm();
    List<PDField> acroFields = acroForm.getFields();
    List<PDField> removeCandidates = getFields( acroFields, field.getPartialName() );
    if( removeAll( acroFields, removeCandidates ) )
        acroForm.setFields( acroFields );
}

removeCandidates.removeAll() が期待どおりに機能しなかったため、ここでカスタム removeAll メソッドを使用したことに注意してください。

ここですべてのコードを提供できなくて申し訳ありませんが、上記を使用して自分で記述できるはずです。

于 2014-07-08T13:27:52.550 に答える
2

コメントするのに十分なポイントはありませんが、フィールドを読み取り専用に設定するという SJohnson の応答は、私にとっては完璧に機能しました。私はPDFBoxでこのようなものを使用しています:

private void setFieldValueAndFlatten(PDAcroForm form, String fieldName, String fieldValue) throws IOException {
    PDField field = form.getField(fieldName);
    if(field != null){
        field.setValue(fieldValue);
        field.setReadonly(true);
    }
}

これにより、フィールド値が書き込まれ、保存後に PDF を開くと、値が設定され、編集できなくなります。

于 2015-08-27T17:58:57.077 に答える
0

これは、PDFBox-Mailinglist からの Thomas の回答です。

COSDictionary でフィールドを取得する必要があります。このコードを試してください...

PDDocument pdDoc = PDDocument.load(new File("E:\\Form-Test.pdf"));
PDDocumentCatalog pdCatalog = pdDoc.getDocumentCatalog();
PDAcroForm acroForm = pdCatalog.getAcroForm();

COSDictionary acroFormDict = acroForm.getDictionary();
COSArray fields = acroFormDict.getDictionaryObject("Fields");
fields.clear();
于 2013-01-25T07:13:16.987 に答える