如何使用 pdfbox 2 在复选框 appearanceStream 上设置边框
How to set border on checkbox appearanceStream using pdfbox 2
我正在使用 PDFBox v2 从头开始创建 pdf,我的复选框外观有问题,当单击该复选框(并且没有单击鼠标)时,复选框的边框不会出现。
我使用了 tilman 在官方文档中提供的代码示例来创建单选按钮并将其改编为创建复选框:
public void drawCheckBox() throws IOException {
for (Entry<String, List<InputCheckBox>> entry : myHash.entrySet()) {
String checkBoxKey = entry.getKey(); // radio buton key
List<InputCheckBox> checkBoxValue = entry.getValue(); // checkbox list(s)
PDCheckBox checkBox = new PDCheckBox(checkBoxValue.get(0).getAcroForm());
checkBox.setPartialName(checkBoxKey);
checkBox.setExportValues(Arrays.asList(checkBoxKey));
// couleur de la checkbox
PDAppearanceCharacteristicsDictionary appearanceCharacteristics = new PDAppearanceCharacteristicsDictionary(
new COSDictionary());
appearanceCharacteristics.setBorderColour(new PDColor(new float[] { 0, 0, 0 }, PDDeviceRGB.INSTANCE));
appearanceCharacteristics.setBackground(new PDColor(new float[] { 1, 1, 1 }, PDDeviceRGB.INSTANCE));
checkBoxValue.get(0).getAcroForm().getFields().add(checkBox);
List<PDAnnotationWidget> widgets = new ArrayList<>();
for (int i = 0; i < checkBoxValue.size(); i++) {
PDAnnotationWidget widget = new PDAnnotationWidget();
widget.setRectangle(new PDRectangle(checkBoxValue.get(i).getLeft(),
checkBoxValue.get(i).getPage().getMediaBox().getHeight()
- (checkBoxValue.get(i).getTop() + checkBoxValue.get(i).getHeight()),
checkBoxValue.get(i).getWidth(), checkBoxValue.get(i).getHeight()));
// border du checkbox
widget.setAppearanceCharacteristics(appearanceCharacteristics);
PDBorderStyleDictionary borderStyleDictionary = new PDBorderStyleDictionary();
borderStyleDictionary.setWidth(1);
borderStyleDictionary.setStyle(PDBorderStyleDictionary.STYLE_SOLID);
// creer les apparence de radio button pour l'état off et l'état activé
COSDictionary apNDict = new COSDictionary();
apNDict.setItem(COSName.Off,
createCheckBoxAppearanceStream(checkBoxValue.get(i).getDocument(), widget, false));
apNDict.setItem(COSName.ON,
createCheckBoxAppearanceStream(checkBoxValue.get(i).getDocument(), widget, true));
PDAppearanceDictionary appearance = new PDAppearanceDictionary();
PDAppearanceEntry appearanceNEntry = new PDAppearanceEntry(apNDict);
appearance.setNormalAppearance(appearanceNEntry);
// appliquer l'apparence dans le widget
widget.setBorderStyle(borderStyleDictionary);
widget.setPage(checkBoxValue.get(i).getPage());
widget.setAppearance(appearance);
widget.setParent(checkBox);
widget.setAppearanceState("Off");
// widget.setAnnotationName(key);
widget.setPrinted(true);
checkBoxValue.get(i).getPage().getAnnotations().add(widget);
widgets.add(widget);
checkBox.setWidgets(widgets);
}
}
}
// les methodes ci_dessous sert a creer l'apparence des checkBox selon leur
// état coché ou non
private static PDAppearanceStream createCheckBoxAppearanceStream(final PDDocument document,
PDAnnotationWidget widget, boolean on) throws IOException {
PDRectangle rect = widget.getRectangle();
PDAppearanceStream onAP = new PDAppearanceStream(document);
onAP.setResources(new PDResources());
onAP.setBBox(new PDRectangle(rect.getWidth(), rect.getHeight()));
PDPageContentStream onAPCS = new PDPageContentStream(document, onAP);
PDAppearanceCharacteristicsDictionary appearanceCharacteristics = widget.getAppearanceCharacteristics();
PDColor backgroundColor = appearanceCharacteristics.getBackground();
PDColor borderColor = appearanceCharacteristics.getBorderColour();
float lineWidth = getLineWidth(widget);
onAPCS.setLineWidth(lineWidth);
onAPCS.setNonStrokingColor(backgroundColor);
onAPCS.fill();
onAPCS.setStrokingColor(borderColor);
onAPCS.stroke();
if (on) {
onAPCS.setFont(PDType1Font.ZAPF_DINGBATS, 14.5f);
onAPCS.beginText();
onAPCS.newLineAtOffset(0, 0);
onAPCS.showText("\u2714");
onAPCS.endText();
onAPCS.fill();
}
onAPCS.close();
return onAP;
}
static float getLineWidth(PDAnnotationWidget widget) {
PDBorderStyleDictionary bs = widget.getBorderStyle();
if (bs != null) {
return bs.getWidth();
}
return 1;
}
这是我得到的结果:
这是我应该拥有的:
您在之前未定义路径的情况下执行路径填充和路径描边:
onAPCS.setNonStrokingColor(backgroundColor);
onAPCS.fill();
onAPCS.setStrokingColor(borderColor);
onAPCS.stroke();
尝试像这样定义路径(作为矩形):
onAPCS.setNonStrokingColor(backgroundColor);
onAPCS.setStrokingColor(borderColor);
onAPCS.addRect(0, 0, rect.getWidth(), rect.getHeight());
onAPCS.fillAndStroke();
(或者您可能想使用稍小的矩形,例如 onAPCS.addRect(1, 1, rect.getWidth() - 2, rect.getHeight() - 2)
。)
顺便说一句,再往下你再次使用 fill
,这次没有任何明显的原因:
if (on) {
...
onAPCS.endText();
onAPCS.fill();
}
你应该删除 fill
因为它严格来说 even 是无效的:fill
和 stroke
只允许在路径定义之后!
我正在使用 PDFBox v2 从头开始创建 pdf,我的复选框外观有问题,当单击该复选框(并且没有单击鼠标)时,复选框的边框不会出现。
我使用了 tilman 在官方文档中提供的代码示例来创建单选按钮并将其改编为创建复选框:
public void drawCheckBox() throws IOException {
for (Entry<String, List<InputCheckBox>> entry : myHash.entrySet()) {
String checkBoxKey = entry.getKey(); // radio buton key
List<InputCheckBox> checkBoxValue = entry.getValue(); // checkbox list(s)
PDCheckBox checkBox = new PDCheckBox(checkBoxValue.get(0).getAcroForm());
checkBox.setPartialName(checkBoxKey);
checkBox.setExportValues(Arrays.asList(checkBoxKey));
// couleur de la checkbox
PDAppearanceCharacteristicsDictionary appearanceCharacteristics = new PDAppearanceCharacteristicsDictionary(
new COSDictionary());
appearanceCharacteristics.setBorderColour(new PDColor(new float[] { 0, 0, 0 }, PDDeviceRGB.INSTANCE));
appearanceCharacteristics.setBackground(new PDColor(new float[] { 1, 1, 1 }, PDDeviceRGB.INSTANCE));
checkBoxValue.get(0).getAcroForm().getFields().add(checkBox);
List<PDAnnotationWidget> widgets = new ArrayList<>();
for (int i = 0; i < checkBoxValue.size(); i++) {
PDAnnotationWidget widget = new PDAnnotationWidget();
widget.setRectangle(new PDRectangle(checkBoxValue.get(i).getLeft(),
checkBoxValue.get(i).getPage().getMediaBox().getHeight()
- (checkBoxValue.get(i).getTop() + checkBoxValue.get(i).getHeight()),
checkBoxValue.get(i).getWidth(), checkBoxValue.get(i).getHeight()));
// border du checkbox
widget.setAppearanceCharacteristics(appearanceCharacteristics);
PDBorderStyleDictionary borderStyleDictionary = new PDBorderStyleDictionary();
borderStyleDictionary.setWidth(1);
borderStyleDictionary.setStyle(PDBorderStyleDictionary.STYLE_SOLID);
// creer les apparence de radio button pour l'état off et l'état activé
COSDictionary apNDict = new COSDictionary();
apNDict.setItem(COSName.Off,
createCheckBoxAppearanceStream(checkBoxValue.get(i).getDocument(), widget, false));
apNDict.setItem(COSName.ON,
createCheckBoxAppearanceStream(checkBoxValue.get(i).getDocument(), widget, true));
PDAppearanceDictionary appearance = new PDAppearanceDictionary();
PDAppearanceEntry appearanceNEntry = new PDAppearanceEntry(apNDict);
appearance.setNormalAppearance(appearanceNEntry);
// appliquer l'apparence dans le widget
widget.setBorderStyle(borderStyleDictionary);
widget.setPage(checkBoxValue.get(i).getPage());
widget.setAppearance(appearance);
widget.setParent(checkBox);
widget.setAppearanceState("Off");
// widget.setAnnotationName(key);
widget.setPrinted(true);
checkBoxValue.get(i).getPage().getAnnotations().add(widget);
widgets.add(widget);
checkBox.setWidgets(widgets);
}
}
}
// les methodes ci_dessous sert a creer l'apparence des checkBox selon leur
// état coché ou non
private static PDAppearanceStream createCheckBoxAppearanceStream(final PDDocument document,
PDAnnotationWidget widget, boolean on) throws IOException {
PDRectangle rect = widget.getRectangle();
PDAppearanceStream onAP = new PDAppearanceStream(document);
onAP.setResources(new PDResources());
onAP.setBBox(new PDRectangle(rect.getWidth(), rect.getHeight()));
PDPageContentStream onAPCS = new PDPageContentStream(document, onAP);
PDAppearanceCharacteristicsDictionary appearanceCharacteristics = widget.getAppearanceCharacteristics();
PDColor backgroundColor = appearanceCharacteristics.getBackground();
PDColor borderColor = appearanceCharacteristics.getBorderColour();
float lineWidth = getLineWidth(widget);
onAPCS.setLineWidth(lineWidth);
onAPCS.setNonStrokingColor(backgroundColor);
onAPCS.fill();
onAPCS.setStrokingColor(borderColor);
onAPCS.stroke();
if (on) {
onAPCS.setFont(PDType1Font.ZAPF_DINGBATS, 14.5f);
onAPCS.beginText();
onAPCS.newLineAtOffset(0, 0);
onAPCS.showText("\u2714");
onAPCS.endText();
onAPCS.fill();
}
onAPCS.close();
return onAP;
}
static float getLineWidth(PDAnnotationWidget widget) {
PDBorderStyleDictionary bs = widget.getBorderStyle();
if (bs != null) {
return bs.getWidth();
}
return 1;
}
这是我得到的结果:
这是我应该拥有的:
您在之前未定义路径的情况下执行路径填充和路径描边:
onAPCS.setNonStrokingColor(backgroundColor);
onAPCS.fill();
onAPCS.setStrokingColor(borderColor);
onAPCS.stroke();
尝试像这样定义路径(作为矩形):
onAPCS.setNonStrokingColor(backgroundColor);
onAPCS.setStrokingColor(borderColor);
onAPCS.addRect(0, 0, rect.getWidth(), rect.getHeight());
onAPCS.fillAndStroke();
(或者您可能想使用稍小的矩形,例如 onAPCS.addRect(1, 1, rect.getWidth() - 2, rect.getHeight() - 2)
。)
顺便说一句,再往下你再次使用 fill
,这次没有任何明显的原因:
if (on) {
...
onAPCS.endText();
onAPCS.fill();
}
你应该删除 fill
因为它严格来说 even 是无效的:fill
和 stroke
只允许在路径定义之后!