如何使用Apache PDFBox在PDF中写入表情符号
PDFBox写入文本与表情符号时表情缺失解决方案
表情缺失的核心原因是PDF默认的14种标准字体均不包含表情符号对应的Unicode字形,需更换支持表情的字体并调整渲染逻辑,具体操作如下:
前置检查
- 先升级PDFBox到2.0.27及以上稳定版本,低版本对多字节Unicode、彩色表情的支持存在缺陷
- 准备支持全量表情的字体,优先选开源无版权风险的Noto Color Emoji,也可以用系统自带的Segoe UI Emoji(Windows)、Apple Color Emoji(macOS)
核心实现步骤
1. 嵌入字体到PDF
必须将字体嵌入PDF,否则接收方设备无对应字体时仍会出现显示缺失,加载字体示例代码:
// 第三个参数设为true代表将字体嵌入PDF文件 PDType0Font emojiFont = PDType0Font.load(document, new File("字体文件本地路径"), true); // 同时加载你用于渲染普通文本的常规字体,比如思源黑体、宋体等 PDType0Font textFont = PDType0Font.load(document, new File("常规字体本地路径"), true);
2. 分段渲染混合内容
常规文本和表情需要用不同字体渲染,所以要先拆分内容中的普通字符和表情字符,分别匹配对应字体后逐个渲染:
PDPageContentStream contentStream = new PDPageContentStream(document, page); String content = "测试普通文本😊 混合表情内容😎"; int length = content.length(); float currentX = 100; // 初始绘制X坐标 float currentY = 700; // 初始绘制Y坐标 float fontSize = 12f; for (int i = 0; i < length; ) { int codePoint = content.codePointAt(i); int charCount = Character.charCount(codePoint); String currentPart = content.substring(i, i + charCount); // JDK11及以上可直接用Character.isEmoji()判断,低版本可以自行维护表情Unicode范围判断逻辑 boolean isEmoji = Character.isEmoji(codePoint); contentStream.beginText(); contentStream.setFont(isEmoji ? emojiFont : textFont, fontSize); contentStream.newLineAtOffset(currentX, currentY); contentStream.showText(currentPart); contentStream.endText(); // 计算当前片段宽度,更新下一段内容的X坐标,避免内容重叠 float partWidth = (isEmoji ? emojiFont : textFont).getStringWidth(currentPart) / 1000 * fontSize; currentX += partWidth; i += charCount; } contentStream.close();
常见异常排查
- 表情显示为黑白:更换带彩色矢量信息的表情字体,同时确认PDFBox版本在2.0.27及以上
- 表情和文本排版错位:可以将表情的字号调整为比普通文本大1-2号,适配显示比例
- 仍显示空白方块:提前在字体查看工具中确认你使用的字体确实包含对应表情的字形,部分精简版字体会删减冷门表情
内容的提问来源于stack exchange,提问作者swapnil nd
相关产品推荐
相关产品推荐

