使用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()
额外建议
- 确认PDF文本编码:如果替换后文本乱码,试试把
StandardCharsets.UTF_8换成StandardCharsets.ISO_8859_1(WinAnsi编码,很多PDF用这个)。 - 别碰图片字节:确保你要替换的文本是唯一的,不会和图片的二进制字节序列重合,否则会破坏图片。最好只替换发票里的明文字段(比如客户名、金额、日期)。
- 用专业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
相关产品推荐
相关产品推荐

