- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我使用这个问题的答案中的代码来创建我的单选按钮: How to Create a Radio Button Group with PDFBox 2.0
在我创建 PDF 并尝试从中读取(以编程方式)选定的值后,这段代码运行良好:
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
}
}
当我在 Acrobat Reader DC 中打开 PDF 时,进行更改并再次保存代码不再起作用。不再有 PDRadioButton 实例,值始终为空字符串。
当我在 Acrobat Touch 中打开 PDF 时,它甚至无法正确显示。
(打开之前用Acrobat Reader DC编辑过的版本,Acrobat Touch可以正确显示)
任何建议代码可能有什么问题?
这是一个行为相同的最小示例:
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();
}
}
}
最佳答案
您的代码显示字段树的顶部。 getFields()
的 javadoc 对此发出警告:
/**
* 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()
要获取所有字段(包括非终端字段),请执行以下操作:
PDDocumentCatalog catalog = doc.getDocumentCatalog();
PDAcroForm form = catalog.getAcroForm();
Iterator<PDField> fieldIterator = form.getFieldIterator();
while (fieldIterator.hasNext())
{
PDField field = fieldIterator.next();
// ... do stuff ...
}
然后您的单选按钮出现。
但是还有一个问题。选择返回为“a”、“b”或“Choice1”而不是“c”。
我能够通过在添加小部件之前添加这段代码来解决这个问题:
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);
它为“Off”和每个按钮的 on-Option 添加了空的外观。
2017 年 1 月 17 日更新:
这是生成带有外观流的单选按钮的源代码:
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();
如果您希望 Adobe 生成外观流(这是代码中的“乱码”),请调用 setNeedAppearances(true)
并删除行 widget.setAppearance(appearance);
。如果你用 Adobe 打开文件并保存它,就会生成外观流,这就是我从那里得到的。如果您查看注释,然后查看 AP 并从那里向下看,您可以使用 PDFDebugger 查看这些内容。
如果您想了解较大按钮的外观流内容,这也是可以使用的策略。
在未来的某个时候,PDFBox 将为按钮生成外观流。涉及一些数学,请参阅 here或在 PDCircleAppearanceHandler 的主干源代码中。
关于java - PDFBox 的单选按钮显示问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41631119/
HTML 部分,只是我代码的一部分: HP: SP: EA: ED: PA: PD:
我有这个简单的脚本。我正在尝试获取选中的值并将它们添加到禁用输入框中的运行总计中。我知道它正在被选中,但它没有更新到输入框,我不确定为什么。谁能帮帮我? function updateF
我在使用自定义背景的单选按钮/复选框时遇到了问题。我在这里设计了它们的样式:Quick Tip: Easy CSS3 Checkboxes and Radio Buttons .主要部分是input在
我可以预见地读取 jQueryUI 单选按钮的值,但是,我无法以编程方式设置它。无论我使用哪种方法更改单选按钮的值,jQueryUI 界面都不会更新其界面。 Yes No
没有展开时 点击展开之后 <div class="flashread_item_box_time"> <span class="
这里是 JQuery 新手。 我有一个大约有 16 个字段的搜索表单,其中大部分是文本框。其余的都是下拉菜单。我在这些字段下方有 3 个单选按钮。当选择第一个时,表单中的某些字段应被禁用。当选择第二个
我目前正在构建一个 Fiori 应用程序用于查看事件(票证)。我必须创建一个饼图,其中包含票证的所有不同状态。当我单击图表的一部分时,它会将我带到包含该状态的所有票证的列表。我可以选择饼图的多个状态,
此代码将在使用 reloadData 刷新 UITableView 后恢复单元格选择: NSIndexPath *selectedIndexPath = [self.tableView indexPa
我正在尝试对 UITableView 单元格进行自定义选择。为此,我在我的单元格上方创建了 UIView,它现在在触摸时出现/消失。但问题是当我按下单元格选择时出现。如果那时我选择任何其他行,它也会被
我所有的复选框、单选框和文本输入都在 ID 的末尾附加了“_boom”。我想抓取这些 id 的页面,检测更改以查看其中是否有任何一个与其原始状态不同,如果是,则将 CSS 应用于页面上名为“保存”的按
我正在寻找一种方法,使多选列表框应显示为普通的单选组合框,但在单击时它应作为允许多选的列表框,如下所示,如电子表格中所示。我正在寻找 CSS HTML 和 javascript 而非 Jquery 中
我有一个 HTML 我想显示为“列表框”(一个同时显示多个元素的框,而不是下拉框)。但是,我只想允许选择一个元素。我还想将盒子的高度(通过 CSS)设置为其容器大小的 100%。 这三件事似乎是相互排
我有一个包含三个部分的付款表格。基本上,第一个是带有乘数的“单选”列表,第二个是带有设置值的“复选框”列表,第三个是带有乘数的下拉列表 ==> (jsfiddle) .为清楚起见,我插入了一个文本框来
我想删除单选按钮,只显示是或否标签。为此,我隐藏了 radio 输入并使用 css3 选择器 (:checked + label) 根据选择更改背景颜色。但由于某种原因,这不起作用。 HTML(来自
我正在使用这个插件http://www.erichynds.com/examples/jquery-ui-multiselect-widget/demos/#single对于多选,并且希望也可以在同一
我收到了这段代码,但我似乎无法正常工作,我查看了之前的问题,但找不到任何与之完全相同的代码。也许这完全是错误的,应该重新开始? 我想要做的是在选择单选按钮时显示一个 div。这是我的代码: jQue
我试图在用户点击输入(单选、复选框或选择)时移除焦点背景,但它不起作用。这些是我放在元素上的样式: .form-holder input[type="radio"]:focus, .form-
我正在使用 Bootstrap 4 并想使用单选按钮和复选框按钮组,但按钮显示的是实际的单选按钮和复选框 UI 元素,如下所示: 上面的例子直接摘自文档。我试过删除并重新安装 Bootstrap 4,
我正在使用 Collection View 进行水平滚动。它工作得很好。现在我想为选择任何单元格设置任何效果。所以,我写了这段代码” func collectionView(collectionVi
我有一个按钮组,其中包含必须充当单选按钮的几个项目。我还需要将它们分成几行并跨越容器的整个宽度。 为此,我使用了 Bootstrap 的类 btn-group-justified ,然后我拆分 元素分
我是一名优秀的程序员,十分优秀!