You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Java替换PDF内容后图片消失,Sed可正常运行求解答

问题:Groovy替换解压后的PDF内容导致图片/Logo消失

我之前也碰到过一模一样的问题!你的情况核心是Groovy/Java处理文件的逻辑和sed本质不同,不小心破坏了PDF里的图片二进制数据,我来帮你拆解原因和解决办法:

先理清楚你的操作流程

  • 下载了一份自由职业作家的PDF发票模板
  • 用pdftk命令解压PDF:pdftk file.pdf output uncompressed.pdf uncompress
  • 用sed替换文本内容,PDF里的Logo和图片都正常显示
  • 换成Groovy(Java)代码替换后,所有图片直接消失

为什么sed没问题,Groovy却搞砸了?

关键差异在文件流的处理方式:

  • sed是纯字节流处理工具,它不会对文件内容做任何编码转换,只是按字节匹配替换指定内容。解压后的PDF虽然大部分是文本,但图片部分是二进制字节流,sed完全不会碰这些非目标字节,所以图片完好无损。
  • 而Groovy/Java如果用File.text、new FileReader()这类字符流读取文件,会默认用系统编码(比如UTF-8)去解析所有字节。图片的二进制字节根本不是合法的字符编码,会被错误解码再编码,写入后图片数据彻底损坏,自然就显示不出来了。

解决办法:用字节流处理,别碰字符编码

在Groovy里必须以字节流的方式读取、替换、写入文件,避免编码转换破坏二进制数据。给你一个可行的示例代码:

import java.nio.charset.StandardCharsets

def inputPath = "uncompressed.pdf"
def outputPath = "modified_invoice.pdf"

// 1. 把整个文件读成字节数组,避免编码转换
byte[] pdfBytes = new File(inputPath).bytes

// 2. 把要替换的文本转成和PDF一致的字节(注意:有些PDF用ISO-8859-1,需根据实际调整)
String oldText = "Freelance Writer Invoice"
String newText = "John Doe - Technical Writing Invoice"
byte[] oldBytes = oldText.getBytes(StandardCharsets.UTF_8)
byte[] newBytes = newText.getBytes(StandardCharsets.UTF_8)

// 3. 字节级替换逻辑(简单实现,适合替换单一明确的文本)
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()
int currentPos = 0
int matchLength = oldBytes.length

while (currentPos <= pdfBytes.length - matchLength) {
    boolean isMatch = true
    // 逐字节对比是否匹配目标文本
    for (int i = 0; i < matchLength; i++) {
        if (pdfBytes[currentPos + i] != oldBytes[i]) {
            isMatch = false
            break
        }
    }
    if (isMatch) {
        // 匹配成功,写入替换后的字节
        outputStream.write(newBytes)
        currentPos += matchLength
    } else {
        // 不匹配,写入当前字节
        outputStream.write(pdfBytes[currentPos])
        currentPos++
    }
}
// 写入剩余的字节
outputStream.write(pdfBytes, currentPos, pdfBytes.length - currentPos)

// 4. 把处理后的字节写入新文件
new File(outputPath).bytes = outputStream.toByteArray()

额外建议

  1. 确认PDF文本编码:如果替换后文本乱码,试试把StandardCharsets.UTF_8换成StandardCharsets.ISO_8859_1(WinAnsi编码,很多PDF用这个)。
  2. 别碰图片字节:确保你要替换的文本是唯一的,不会和图片的二进制字节序列重合,否则会破坏图片。最好只替换发票里的明文字段(比如客户名、金额、日期)。
  3. 用专业PDF库更省心:如果需要频繁编辑PDF,推荐用Apache PDFBox或iText这类专门的库,它们能直接操作PDF的内容结构,不需要手动解压替换,更安全稳定。比如用PDFBox的简单示例:
@Grab('org.apache.pdfbox:pdfbox:2.0.32')
import org.apache.pdfbox.pdmodel.PDDocument
import org.apache.pdfbox.pdmodel.PDPageContentStream
import org.apache.pdfbox.pdmodel.font.PDType1Font

def doc = PDDocument.load(new File("file.pdf"))
def firstPage = doc.getPage(0)

// 先白色覆盖原文本区域,再写入新文本
PDPageContentStream contentStream = new PDPageContentStream(doc, firstPage, PDPageContentStream.AppendMode.APPEND, true)
// 白色矩形覆盖原发票抬头位置(需自己调整坐标和尺寸)
contentStream.setNonStrokingColor(255, 255, 255)
contentStream.addRect(150, 750, 300, 30)
contentStream.fill()

// 写入新的发票抬头
contentStream.setNonStrokingColor(0, 0, 0)
contentStream.beginText()
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 16)
contentStream.newLineAtOffset(150, 755)
contentStream.showText("Jane Smith - Creative Writing Invoice")
contentStream.endText()

contentStream.close()
doc.save(new File("modified_invoice.pdf"))
doc.close()

内容的提问来源于stack exchange,提问作者mightguy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:13:02