Radiobutton显示PDFBox的问题 [英] Radiobutton display problems with PDFBox

查看:135
本文介绍了Radiobutton显示PDFBox的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用了这个问题答案中的代码来创建我的radiobuttons:



当我在Acrobat Touch中打开PDF时,它甚至无法正常显示。



(当我打开之前由Acrobat Reader DC编辑的版本时,Acrobat Touch可以显示它是正确的)



任何建议代码可能有什么问题?



这是一个行为最小的例子相同:

 包测试; 

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceCharacteristicsDictionary;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDRadioButton;


公共类WriterTest {
public static void main(String [] args){
try {
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4);

document.addPage(page);

PDAcroForm acroForm = new PDAcroForm(document);
acroForm.setNeedAppearances(true);
acroForm.setXFA(null);
document.getDocumentCatalog()。setAcroForm(acroForm);

PDFont font = PDType1Font.HELVETICA;

PDResources res = new PDResources();
COSName fontName = res.add(font);
acroForm.setDefaultResources(res);
acroForm.setDefaultAppearance('/'+ fontName.getName()+10 Tf 0 g);

PDPageContentStream contents = new PDPageContentStream(document,page);

List< String> options = Arrays.asList(a,b,c);
PDRadioButton radioButton = new PDRadioButton(acroForm);
radioButton.setPartialName(RadioButtonParent);
radioButton.setExportValues(options);
radioButton.getCOSObject()。setName(COSName.DV,options.get(1));

List< PDAnnotationWidget> widgets = new ArrayList<>();
for(int i = 0; i< options.size(); i ++){
PDRadioButton subRadioButtons = new PDRadioButton(acroForm);
subRadioButtons.setPartialName(RadioButton);

PDAppearanceCharacteristicsDictionary fieldAppearance = new PDAppearanceCharacteristicsDictionary(new COSDictionary());
fieldAppearance.setBorderColour(new PDColor(new float [] {0,0,0},PDDeviceRGB.INSTANCE));

PDAnnotationWidget widget = subRadioButtons.getWidgets()。get(0);
widget.setRectangle(new PDRectangle(30,811 - i *(21),16,16));
widget.setAppearanceCharacteristics(fieldAppearance);

widgets.add(widget);
page.getAnnotations()。add(widget);

contents.beginText();
contents.setFont(font,10);
contents.newLineAtOffset(56,811 - i *(21)+ 4);
contents.showText(options.get(i));
contents.endText();
}
radioButton.setWidgets(小部件);
acroForm.getFields()。add(radioButton);

contents.close();
try(FileOutputStream output = new FileOutputStream(test.pdf)){
document.save(output);
}
document.close();
} catch(IOException e){
e.printStackTrace();
}
}
}


解决方案

您的代码显示字段树的顶部。 getFields()的javadoc警告:

  / ** 
*这将返回所有文档的根域。
*
*一个字段可能有子字段(非终端字段)或不是
*有子字段是字段(终端字段)。
*
* AcroForm中的字段以树形结构组织。文档根字段
*可以是终端字段,非终端字段或两者的混合。非终端字段
*标记分支,可以使用{@link PDNonTerminalField#getChildren()}检索哪些内容。
*
* @return文件根目录列表。
*
* /
公开列表< PDField> getFields()

要获取所有字段(包括非终端字段),请执行以下操作:

  PDDocumentCatalog catalog = doc.getDocumentCatalog(); 
PDAcroForm form = catalog.getAcroForm();
Iterator< PDField> fieldIterator = form.getFieldIterator();
while(fieldIterator.hasNext())
{
PDField field = fieldIterator.next();
// ...做东西...
}

然后你的单选按钮出现。



但是还有另一个问题。选择返回为a,b或Choice1而不是c。



我能够通过在添加之前添加此代码段来解决此问题小部件:

  PDAppearanceDictionary外观=新的PDAppearanceDictionary(); 
COSDictionary dict = new COSDictionary();
dict.setItem(COSName.getPDFName(Off),new COSDictionary());
dict.setItem(COSName.getPDFName(options.get(i)),new COSDictionary());
PDAppearanceEntry appearanceEntry = new PDAppearanceEntry(dict);
appearance.setNormalAppearance(appearanceEntry);
widget.setAppearance(appearance);

它为关闭和每个按钮的开启选项添加空白外观。



更新17.1.2017:



以下是生成带外观流的单选按钮的源代码:

  PDDocument document = new PDDocument(); 
PDPage page = new PDPage(PDRectangle.A4);

document.addPage(page);

PDAcroForm acroForm = new PDAcroForm(document);

//不需要,我们有外观流
//acroForm.setNeedAppearances(true);

acroForm.setXFA(null);
document.getDocumentCatalog()。setAcroForm(acroForm);

PDFont font = PDType1Font.HELVETICA;

PDResources res = new PDResources();
COSName fontName = res.add(font);
acroForm.setDefaultResources(res);
acroForm.setDefaultAppearance('/'+ fontName.getName()+10 Tf 0 g);

PDPageContentStream contents = new PDPageContentStream(document,page);

List< String> options = Arrays.asList(a,b,c);
PDRadioButton radioButton = new PDRadioButton(acroForm);
radioButton.setPartialName(RadioButtonParent);根据Maruan Sahyoun的建议删除
//,setValue不再工作
//radioButton.setExportValues(options);
radioButton.getCOSObject()。setName(COSName.DV,options.get(1));
radioButton.setFieldFlags(49152);
int on = 1;

List< PDAnnotationWidget> widgets = new ArrayList<>();
for(int i = 0; i< options.size(); i ++)
{
PDAppearanceCharacteristicsDictionary fieldAppearance = new PDAppearanceCharacteristicsDictionary(new COSDictionary());
fieldAppearance.setBorderColour(new PDColor(new float [] {0,0,0},PDDeviceRGB.INSTANCE));
PDAnnotationWidget widget = new PDAnnotationWidget();
widget.setRectangle(new PDRectangle(30,811 - i *(21),16,16));
widget.setAppearanceCharacteristics(fieldAppearance);
widget.setAnnotationFlags(4);
widget.setPage(页面);
widget.setParent(radioButton);

字符串offNString =0 G \ n
+q \ n
+1 0 0 1 8 8 cm \ n
+7.5 0 m\\\

+7.5 4.1423 4.1423 7.5 0 7.5 c\ n
+ - 4.1423 7.5 -7.5 4.1423 -7.5 0 c\ n
+-7.5 -4.1423 -4.1423 -7.5 0 -7.5 c\\\

+4.1423 -7.5 7.5 -4.1423 7.5 0 c\ n
+s \ n
+Q;
字符串onNString =0 G \ n
+q \ n
+1 0 0 1 8 8 cm \ n
+7.5 0 m \ n
+7.5 4.1423 4.1423 7.5 0 7.5 c\\\

+-4.1423 7.5 -7.5 4.1423 -7.5 0 c\ n
+ - 7.5 -4.1423 -4.1423 -7.5 0 -7.5 c\\\

+4.1423 -7.5 7.5 -4.1423 7.5 0 c\\\

+s \ n
+ Q $ \\ n
+q \ n
+1 0 0 1 8 8 cm \ n
+3.5 0 m\\\

+3.5 1.9331 1.9331 3.5 0 3.5 c\ n
+-1.9331 3.5 -3.5 1.9331 -3.5 0 c\ n
+ - 3.5 -9.9331 -1.9331 -3.5 0 -3.5 c'h
+1.9331 -3.5 3.5 -1.9331 3.5 0 c\\\

+f\\\

+Q;
String offDString =0.749023 g\\\

+q\ n
+1 0 0 1 8 8 cm\\\

+8 0 m \ n
+8 4.4185 4.4185 8 0 8 c\ n
+-4.4185 8 -8 4.4185 -8 0 c\ n
+ - 8 -4.4185 -4.4185 -8 0 -8 c\\\

+4.4185 -8 8 -4.4185 8 0 c\\\

+f\\\

+ Q $ \\ n
+0 G \ n
+q \ n
+1 0 0 1 8 8 cm \ n
+ 7.5 0 m\\\

+7.5 4.1423 4.1423 7.5 0 7.5 c\ n
+ - 4.1423 7.5 -7.5 4.1423 -7.5 0 c\ n
+ -7.5 -4.1423 -4.1423 -7.5 0 -7.5 c\\\

+4.1423 -7.5 7.5 -4.1423 7.5 0 c\\\

+s \ n
+Q;
String onDString =0.749023 g\\\

+q\ n
+1 0 0 1 8 8 cm\\\

+8 0 m \ n
+8 4.4185 4.4185 8 0 8 c\ n
+-4.4185 8 -8 4.4185 -8 0 c\ n
+ - 8 -4.4185 -4.4185 -8 0 -8 c\\\

+4.4185 -8 8 -4.4185 8 0 c\\\

+f\\\

+ Q $ \\ n
+0 G \ n
+q \ n
+1 0 0 1 8 8 cm \ n
+ 7.5 0 m\\\

+7.5 4.1423 4.1423 7.5 0 7.5 c\ n
+ - 4.1423 7.5 -7.5 4.1423 -7.5 0 c\ n
+ -7.5 -4.1423 -4.1423 -7.5 0 -7.5 c\\\

+4.1423 -7.5 7.5 -4.1423 7.5 0 c\\\

+s \ n
+Q \ n
+0 g\\\

+q\ n
+1 0 0 1 8 8 cm \ n
+3.5 0 m\\\

+3.5 1.9331 1.9331 3.5 0 3.5 c\ n
+-1.9331 3.5 -3.5 1.9331 -3.5 0 c \ n
+-3.5 -1.9331 -1.9331 -3.5 0 -3.5 c\\\

+1.9331 -3.5 3.5 -1.9331 3.5 0 c\\\

+f\\\

+Q;
COSDictionary apNDict = new COSDictionary();
COSStream offNStream = new COSStream();
offNStream.setItem(COSName.BBOX,new PDRectangle(16,16));
offNStream.setItem(COSName.FORMTYPE,COSInteger.ONE);
offNStream.setItem(COSName.TYPE,COSName.XOBJECT);
offNStream.setItem(COSName.SUBTYPE,COSName.FORM);
OutputStream os = offNStream.createOutputStream(COSName.FLATE_DECODE);
os.write(offNString.getBytes());
os.close();
apNDict.setItem(COSName.Off,offNStream);

COSStream onNStream = new COSStream();
onNStream.setItem(COSName.BBOX,new PDRectangle(16,16));
onNStream.setItem(COSName.FORMTYPE,COSInteger.ONE);
onNStream.setItem(COSName.TYPE,COSName.XOBJECT);
onNStream.setItem(COSName.SUBTYPE,COSName.FORM);
os = onNStream.createOutputStream(COSName.FLATE_DECODE);
os.write(onNString.getBytes());
os.close();
apNDict.setItem(options.get(i),onNStream);

COSDictionary apDDict = new COSDictionary();
COSStream offDStream = new COSStream();
offDStream.setItem(COSName.BBOX,new PDRectangle(16,16));
offDStream.setItem(COSName.FORMTYPE,COSInteger.ONE);
offDStream.setItem(COSName.TYPE,COSName.XOBJECT);
offDStream.setItem(COSName.SUBTYPE,COSName.FORM);
os = offDStream.createOutputStream(COSName.FLATE_DECODE);
os.write(offDString.getBytes());
os.close();
apDDict.setItem(COSName.Off,offDStream);

COSStream onDStream = new COSStream();
onDStream.setItem(COSName.BBOX,new PDRectangle(16,16));
onDStream.setItem(COSName.FORMTYPE,COSInteger.ONE);
onDStream.setItem(COSName.TYPE,COSName.XOBJECT);
onDStream.setItem(COSName.SUBTYPE,COSName.FORM);
os = onDStream.createOutputStream(COSName.FLATE_DECODE);
os.write(onDString.getBytes());
os.close();
apDDict.setItem(options.get(i),onDStream);

PDAppearanceDictionary外观=新的PDAppearanceDictionary();
PDAppearanceEntry appearanceNEntry = new PDAppearanceEntry(apNDict);
appearance.setNormalAppearance(appearanceNEntry);
PDAppearanceEntry appearanceDEntry = new PDAppearanceEntry(apDDict);
appearance.setDownAppearance(appearanceDEntry);

widget.setAppearance(appearance);

widget.setAppearanceState(i == on?options.get(i):Off);

widgets.add(widget);
page.getAnnotations()。add(widget);

contents.beginText();
contents.setFont(font,10);
contents.newLineAtOffset(56,811 - i *(21)+ 4);
contents.showText(options.get(i));
contents.endText();
}
radioButton.setWidgets(小部件);
acroForm.getFields()。add(radioButton);

contents.close();
try(FileOutputStream output = new FileOutputStream(test.pdf))
{
document.save(output);
}
document.close();

如果您希望Adobe生成外观流(代码中的乱码),请致电 setNeedAppearances(true)并删除行 widget.setAppearance(appearance); 。如果您使用Adobe打开文件并保存它,将生成外观流,这就是我从中获取这些内容的地方。如果你查看注释,你可以用PDFDebugger看到这些,然后是AP并从那里开始。



如果你想知道外观流,这也是使用的策略更大按钮的内容。



将来某些时候,PDFBox将生成按钮的外观流。涉及一些数学,请参阅此处或PDCircleAppearanceHandler中的主干源代码。


I used the code from the answer from this question to create my radiobuttons: How to Create a Radio Button Group with PDFBox 2.0

After I created my PDF and tried to read the (programatically) selected value from it, this code worked fine:

    PDDocumentCatalog catalog = doc.getDocumentCatalog();
    PDAcroForm form = catalog.getAcroForm();
    List<PDField> fields = form.getFields();

    for(PDField field: fields) {
        Object value = field.getValueAsString();
        String name = field.getFullyQualifiedName();
        if (field instanceof PDRadioButton) {
            // value is correct and field is instance of PDRadioButton works too
        }

    }

When I open the PDF in Acrobat Reader DC, make changes and save it again the code doesn't work anymore. There is no instance of PDRadioButton anymore and the value is always an empty string.

When I open the PDF in Acrobat Touch it doesn't even display properly.

(When I open the version that was previously edited by Acrobat Reader DC, Acrobat Touch can display it correctly)

Any suggestions what may be wrong with the code?

Here is a minimal example that behaves the same:

package test;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceCharacteristicsDictionary;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDRadioButton;


public class WriterTest {
    public static void main(String[] args) {
        try {
            PDDocument document = new PDDocument();
            PDPage page = new PDPage(PDRectangle.A4);

            document.addPage(page);

            PDAcroForm acroForm = new PDAcroForm(document);
            acroForm.setNeedAppearances(true);
            acroForm.setXFA(null);
            document.getDocumentCatalog().setAcroForm(acroForm);

            PDFont font = PDType1Font.HELVETICA;

            PDResources res = new PDResources();
            COSName fontName = res.add(font);
            acroForm.setDefaultResources(res);
            acroForm.setDefaultAppearance('/' + fontName.getName() + " 10 Tf 0 g");

            PDPageContentStream contents = new PDPageContentStream(document, page);

            List<String> options = Arrays.asList("a", "b", "c");
            PDRadioButton radioButton = new PDRadioButton(acroForm);
            radioButton.setPartialName("RadioButtonParent");
            radioButton.setExportValues(options);
            radioButton.getCOSObject().setName(COSName.DV, options.get(1));

            List<PDAnnotationWidget> widgets = new ArrayList<>();
            for (int i = 0; i < options.size(); i++) {
                PDRadioButton subRadioButtons = new PDRadioButton(acroForm);
                subRadioButtons.setPartialName("RadioButton");

                PDAppearanceCharacteristicsDictionary fieldAppearance = new PDAppearanceCharacteristicsDictionary(new COSDictionary());
                fieldAppearance.setBorderColour(new PDColor(new float[] { 0, 0, 0 }, PDDeviceRGB.INSTANCE));

                PDAnnotationWidget widget = subRadioButtons.getWidgets().get(0);
                widget.setRectangle(new PDRectangle(30, 811 - i * (21), 16, 16));
                widget.setAppearanceCharacteristics(fieldAppearance);

                widgets.add(widget);
                page.getAnnotations().add(widget);

                contents.beginText();
                contents.setFont(font, 10);
                contents.newLineAtOffset(56, 811 - i * (21) + 4);
                contents.showText(options.get(i));
                contents.endText();
            }
            radioButton.setWidgets(widgets);
            acroForm.getFields().add(radioButton);

            contents.close();
            try (FileOutputStream output = new FileOutputStream("test.pdf")) {
                document.save(output);
            }
            document.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

解决方案

Your code displays the top of the field tree. The javadoc of getFields() warns about this:

/**
 * This will return all of the documents root fields.
 * 
 * A field might have children that are fields (non-terminal field) or does not
 * have children which are fields (terminal fields).
 * 
 * The fields within an AcroForm are organized in a tree structure. The documents root fields 
 * might either be terminal fields, non-terminal fields or a mixture of both. Non-terminal fields
 * mark branches which contents can be retrieved using {@link PDNonTerminalField#getChildren()}.
 * 
 * @return A list of the documents root fields.
 * 
 */
public List<PDField> getFields()

To get all the fields (this includes non terminal fields), do this:

PDDocumentCatalog catalog = doc.getDocumentCatalog();
PDAcroForm form = catalog.getAcroForm();
Iterator<PDField> fieldIterator = form.getFieldIterator();
while (fieldIterator.hasNext())
{
    PDField field = fieldIterator.next();
    // ... do stuff ...
}

Then your radio button appears.

However there are still another problem. The choice is returned as "a", "b" or "Choice1" instead of "c".

I was able to fix that by adding this code segment before adding the widget:

PDAppearanceDictionary appearance = new PDAppearanceDictionary();
COSDictionary dict = new COSDictionary();
dict.setItem(COSName.getPDFName("Off"), new COSDictionary());
dict.setItem(COSName.getPDFName(options.get(i)), new COSDictionary());
PDAppearanceEntry appearanceEntry = new PDAppearanceEntry(dict);
appearance.setNormalAppearance(appearanceEntry);
widget.setAppearance(appearance);

It adds empty appearances for "Off" and for the on-Option to each button.

Update 17.1.2017:

Here's source code to generate radio buttons with appearance streams:

PDDocument document = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4);

document.addPage(page);

PDAcroForm acroForm = new PDAcroForm(document);

// not needed, we have appearance streams
//acroForm.setNeedAppearances(true);

acroForm.setXFA(null);
document.getDocumentCatalog().setAcroForm(acroForm);

PDFont font = PDType1Font.HELVETICA;

PDResources res = new PDResources();
COSName fontName = res.add(font);
acroForm.setDefaultResources(res);
acroForm.setDefaultAppearance('/' + fontName.getName() + " 10 Tf 0 g");

PDPageContentStream contents = new PDPageContentStream(document, page);

List<String> options = Arrays.asList("a", "b", "c");
PDRadioButton radioButton = new PDRadioButton(acroForm);
radioButton.setPartialName("RadioButtonParent");
// removed per advice of Maruan Sahyoun, setValue didn't work anymore
//radioButton.setExportValues(options);
radioButton.getCOSObject().setName(COSName.DV, options.get(1));
radioButton.setFieldFlags(49152);
int on = 1;

List<PDAnnotationWidget> widgets = new ArrayList<>();
for (int i = 0; i < options.size(); i++)
{
    PDAppearanceCharacteristicsDictionary fieldAppearance = new PDAppearanceCharacteristicsDictionary(new COSDictionary());
    fieldAppearance.setBorderColour(new PDColor(new float[] { 0, 0, 0 }, PDDeviceRGB.INSTANCE));
    PDAnnotationWidget widget = new PDAnnotationWidget();
    widget.setRectangle(new PDRectangle(30, 811 - i * (21), 16, 16));
    widget.setAppearanceCharacteristics(fieldAppearance);
    widget.setAnnotationFlags(4);
    widget.setPage(page);
    widget.setParent(radioButton);

    String offNString = "0 G\n"
            + "q\n"
            + "  1 0 0 1 8 8 cm\n"
            + "  7.5 0 m\n"
            + "  7.5 4.1423 4.1423 7.5 0 7.5 c\n"
            + "  -4.1423 7.5 -7.5 4.1423 -7.5 0 c\n"
            + "  -7.5 -4.1423 -4.1423 -7.5 0 -7.5 c\n"
            + "  4.1423 -7.5 7.5 -4.1423 7.5 0 c\n"
            + "  s\n"
            + "Q";
    String onNString = "0 G\n"
            + "q\n"
            + "  1 0 0 1 8 8 cm\n"
            + "  7.5 0 m\n"
            + "  7.5 4.1423 4.1423 7.5 0 7.5 c\n"
            + "  -4.1423 7.5 -7.5 4.1423 -7.5 0 c\n"
            + "  -7.5 -4.1423 -4.1423 -7.5 0 -7.5 c\n"
            + "  4.1423 -7.5 7.5 -4.1423 7.5 0 c\n"
            + "  s\n"
            + "Q\n"
            + "q\n"
            + "  1 0 0 1 8 8 cm\n"
            + "  3.5 0 m\n"
            + "  3.5 1.9331 1.9331 3.5 0 3.5 c\n"
            + "  -1.9331 3.5 -3.5 1.9331 -3.5 0 c\n"
            + "  -3.5 -1.9331 -1.9331 -3.5 0 -3.5 c\n"
            + "  1.9331 -3.5 3.5 -1.9331 3.5 0 c\n"
            + "  f\n"
            + "Q";
    String offDString = "0.749023 g\n"
            + "q\n"
            + "  1 0 0 1 8 8 cm\n"
            + "  8 0 m\n"
            + "  8 4.4185 4.4185 8 0 8 c\n"
            + "  -4.4185 8 -8 4.4185 -8 0 c\n"
            + "  -8 -4.4185 -4.4185 -8 0 -8 c\n"
            + "  4.4185 -8 8 -4.4185 8 0 c\n"
            + "  f\n"
            + "Q\n"
            + "0 G\n"
            + "q\n"
            + "  1 0 0 1 8 8 cm\n"
            + "  7.5 0 m\n"
            + "  7.5 4.1423 4.1423 7.5 0 7.5 c\n"
            + "  -4.1423 7.5 -7.5 4.1423 -7.5 0 c\n"
            + "  -7.5 -4.1423 -4.1423 -7.5 0 -7.5 c\n"
            + "  4.1423 -7.5 7.5 -4.1423 7.5 0 c\n"
            + "  s\n"
            + "Q";
    String onDString = "0.749023 g\n"
            + "q\n"
            + "  1 0 0 1 8 8 cm\n"
            + "  8 0 m\n"
            + "  8 4.4185 4.4185 8 0 8 c\n"
            + "  -4.4185 8 -8 4.4185 -8 0 c\n"
            + "  -8 -4.4185 -4.4185 -8 0 -8 c\n"
            + "  4.4185 -8 8 -4.4185 8 0 c\n"
            + "  f\n"
            + "Q\n"
            + "0 G\n"
            + "q\n"
            + "  1 0 0 1 8 8 cm\n"
            + "  7.5 0 m\n"
            + "  7.5 4.1423 4.1423 7.5 0 7.5 c\n"
            + "  -4.1423 7.5 -7.5 4.1423 -7.5 0 c\n"
            + "  -7.5 -4.1423 -4.1423 -7.5 0 -7.5 c\n"
            + "  4.1423 -7.5 7.5 -4.1423 7.5 0 c\n"
            + "  s\n"
            + "Q\n"
            + "0 g\n"
            + "q\n"
            + "  1 0 0 1 8 8 cm\n"
            + "  3.5 0 m\n"
            + "  3.5 1.9331 1.9331 3.5 0 3.5 c\n"
            + "  -1.9331 3.5 -3.5 1.9331 -3.5 0 c\n"
            + "  -3.5 -1.9331 -1.9331 -3.5 0 -3.5 c\n"
            + "  1.9331 -3.5 3.5 -1.9331 3.5 0 c\n"
            + "  f\n"
            + "Q";
    COSDictionary apNDict = new COSDictionary();
    COSStream offNStream = new COSStream();
    offNStream.setItem(COSName.BBOX, new PDRectangle(16, 16));
    offNStream.setItem(COSName.FORMTYPE, COSInteger.ONE);
    offNStream.setItem(COSName.TYPE, COSName.XOBJECT);
    offNStream.setItem(COSName.SUBTYPE, COSName.FORM);
    OutputStream os = offNStream.createOutputStream(COSName.FLATE_DECODE);
    os.write(offNString.getBytes());
    os.close();
    apNDict.setItem(COSName.Off, offNStream);

    COSStream onNStream = new COSStream();
    onNStream.setItem(COSName.BBOX, new PDRectangle(16, 16));
    onNStream.setItem(COSName.FORMTYPE, COSInteger.ONE);
    onNStream.setItem(COSName.TYPE, COSName.XOBJECT);
    onNStream.setItem(COSName.SUBTYPE, COSName.FORM);
    os = onNStream.createOutputStream(COSName.FLATE_DECODE);
    os.write(onNString.getBytes());
    os.close();
    apNDict.setItem(options.get(i), onNStream);

    COSDictionary apDDict = new COSDictionary();
    COSStream offDStream = new COSStream();
    offDStream.setItem(COSName.BBOX, new PDRectangle(16, 16));
    offDStream.setItem(COSName.FORMTYPE, COSInteger.ONE);
    offDStream.setItem(COSName.TYPE, COSName.XOBJECT);
    offDStream.setItem(COSName.SUBTYPE, COSName.FORM);
    os = offDStream.createOutputStream(COSName.FLATE_DECODE);
    os.write(offDString.getBytes());
    os.close();
    apDDict.setItem(COSName.Off, offDStream);

    COSStream onDStream = new COSStream();
    onDStream.setItem(COSName.BBOX, new PDRectangle(16, 16));
    onDStream.setItem(COSName.FORMTYPE, COSInteger.ONE);
    onDStream.setItem(COSName.TYPE, COSName.XOBJECT);
    onDStream.setItem(COSName.SUBTYPE, COSName.FORM);
    os = onDStream.createOutputStream(COSName.FLATE_DECODE);
    os.write(onDString.getBytes());
    os.close();
    apDDict.setItem(options.get(i), onDStream);

    PDAppearanceDictionary appearance = new PDAppearanceDictionary();
    PDAppearanceEntry appearanceNEntry = new PDAppearanceEntry(apNDict);
    appearance.setNormalAppearance(appearanceNEntry);
    PDAppearanceEntry appearanceDEntry = new PDAppearanceEntry(apDDict);
    appearance.setDownAppearance(appearanceDEntry);

    widget.setAppearance(appearance);

    widget.setAppearanceState(i == on ? options.get(i) : "Off");

    widgets.add(widget);
    page.getAnnotations().add(widget);

    contents.beginText();
    contents.setFont(font, 10);
    contents.newLineAtOffset(56, 811 - i * (21) + 4);
    contents.showText(options.get(i));
    contents.endText();
}
radioButton.setWidgets(widgets);
acroForm.getFields().add(radioButton);

contents.close();
try (FileOutputStream output = new FileOutputStream("test.pdf"))
{
    document.save(output);
}
document.close();

If you want Adobe to generate the appearance streams (that's the "gibberish" in the code), call setNeedAppearances(true) and remove the line widget.setAppearance(appearance);. If you open the file with Adobe and save it, the appearance streams will be generated, and that is where I got these from. You can see these with PDFDebugger if you look at the annotations, then AP and go down from there.

That's also the strategy to use if you want to know the appearance stream content for bigger buttons.

Some time in the future PDFBox will generate the appearance streams for buttons. There is some math involved, see here or in the trunk source code in PDCircleAppearanceHandler.

这篇关于Radiobutton显示PDFBox的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆