使用PDFBox(Java)添加PDF按钮部件/标注无显示,求解决
PDFBox添加按钮标注不显示的问题修复
你的代码核心问题在于只设置了按钮按下状态的外观(DownAppearance),但没有设置默认的正常状态外观(NormalAppearance),PDF阅读器默认加载正常状态的外观,所以按钮不会显示。另外createAppearanceStream方法需要具体实现来绘制按钮的视觉样式。
以下是修正后的完整代码:
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDRectangle; import org.apache.pdfbox.pdmodel.interactive.action.PDActionJavaScript; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream; import org.apache.pdfbox.pdmodel.PDPageContentStream; import java.io.IOException; import java.util.List; public class AddButtonToPDF { public static void main(String[] args) throws IOException { // 创建PDF文档对象 PDDocument document = new PDDocument(); System.out.println("PDF created"); PDPage page = new PDPage(PDRectangle.A4); document.addPage(page); PDAnnotationWidget buttonWidget = new PDAnnotationWidget(); // 设置按钮位置和尺寸(PDF坐标:左下角为原点,x向右,y向上) PDRectangle buttonRect = new PDRectangle(100, 100, 100, 30); buttonWidget.setRectangle(buttonRect); buttonWidget.setPage(page); buttonWidget.setPrinted(true); // 设置按钮点击事件 PDActionJavaScript javascript = new PDActionJavaScript("app.alert('Button Clicked!');"); buttonWidget.setAction(javascript); // 创建外观字典,同时设置正常状态和按下状态的外观 PDAppearanceDictionary appearanceDict = new PDAppearanceDictionary(); // 正常状态外观 PDAppearanceStream normalAppearance = createAppearanceStream(document, buttonRect, "Click Me"); appearanceDict.setNormalAppearance(normalAppearance); // 按下状态外观(可以和正常状态区分,比如换颜色) PDAppearanceStream downAppearance = createAppearanceStream(document, buttonRect, "Clicked!", true); appearanceDict.setDownAppearance(downAppearance); buttonWidget.setAppearance(appearanceDict); // 将按钮添加到页面标注列表 List<PDAnnotation> annotations = page.getAnnotations(); annotations.add(buttonWidget); page.setAnnotations(annotations); document.save("C:\\Musaub\\Hp_Notebook\\Freelancing\\Jobs\\3d_Point_Cloud_Floorplan\\E57_Files\\Bundle_4\\Panoramas\\PDF 23-282_out.pdf"); document.close(); } // 实现外观流绘制:绘制按钮边框、背景和文字 private static PDAppearanceStream createAppearanceStream(PDDocument document, PDRectangle rect, String text) throws IOException { return createAppearanceStream(document, rect, text, false); } private static PDAppearanceStream createAppearanceStream(PDDocument document, PDRectangle rect, String text, boolean isDown) throws IOException { PDAppearanceStream appearanceStream = new PDAppearanceStream(document); appearanceStream.setBBox(rect); // 外观流的边界必须和按钮矩形一致 try (PDPageContentStream contentStream = new PDPageContentStream(document, appearanceStream)) { // 绘制按钮背景 contentStream.setNonStrokingColor(isDown ? 0.7f : 0.9f); // 按下时颜色稍深 contentStream.addRect(rect.getLowerLeftX(), rect.getLowerLeftY(), rect.getWidth(), rect.getHeight()); contentStream.fill(); // 绘制按钮边框 contentStream.setStrokingColor(0.2f); contentStream.addRect(rect.getLowerLeftX(), rect.getLowerLeftY(), rect.getWidth(), rect.getHeight()); contentStream.stroke(); // 绘制按钮文字 contentStream.beginText(); contentStream.setFont(org.apache.pdfbox.pdmodel.font.PDType1Font.HELVETICA_BOLD, 12); contentStream.setNonStrokingColor(0f); // 计算文字居中位置 float textWidth = org.apache.pdfbox.pdmodel.font.PDType1Font.HELVETICA_BOLD.getStringWidth(text) / 1000 * 12; float textX = rect.getLowerLeftX() + (rect.getWidth() - textWidth) / 2; float textY = rect.getLowerLeftY() + (rect.getHeight() - 12) / 2 + 4; // 微调垂直居中 contentStream.newLineAtOffset(textX, textY); contentStream.showText(text); contentStream.endText(); } return appearanceStream; } }
关键修改点说明:
- 添加NormalAppearance:必须为按钮设置默认的正常状态外观,这是PDF阅读器显示按钮的基础。
- 完善createAppearanceStream实现:该方法负责绘制按钮的视觉样式,包括背景、边框和文字,同时确保外观流的BBox与按钮矩形匹配,否则绘制内容可能被裁剪。
- 区分按下状态外观:可选地为按下状态设置不同的样式,提升交互反馈。
内容的提问来源于stack exchange,提问作者Musaub Shaikh
相关产品推荐
相关产品推荐

