如何用iText7仅移除PDF每页的QR码且不破坏其他内容?
使用iText7移除PDF中的QR码且避免页面内容变形的解决方案
问题分析
你当前的代码直接调用stream.clear()清空QR码对应的PdfStream,这会破坏PDF的资源引用结构——页面内容流仍然保留着对该XObject的绘制指令,但资源本身已失效,导致渲染时出现文本或组件变形。此外,仅通过尺寸判断QR码的逻辑极易误删其他方形图片,准确性不足。
解决方案
正确的做法是修改页面内容流,移除对目标QR码XObject的绘制指令,而非直接清空资源流。同时,建议结合图像内容识别(如ZXing库)来精准判断QR码,避免误操作。
步骤1:精准识别QR码
使用ZXing库检测图像是否为QR码,替代仅靠尺寸判断的逻辑:
import com.google.zxing.BinaryBitmap; import com.google.zxing.MultiFormatReader; import com.google.zxing.Result; import com.google.zxing.client.j2se.BufferedImageLuminanceSource; import com.google.zxing.common.HybridBinarizer; import java.awt.image.BufferedImage; private static boolean isQRCode(PdfImageXObject image) { try { BufferedImage bufferedImage = image.getBufferedImage(); BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(bufferedImage))); Result result = new MultiFormatReader().decode(bitmap); return result != null; } catch (Exception e) { return false; } }
步骤2:修改页面内容流,移除QR码绘制指令
通过PdfCanvasProcessor遍历页面内容流,拦截并移除绘制QR码XObject的Do指令:
import com.itextpdf.kernel.pdf.PdfDocument; import com.itextpdf.kernel.pdf.PdfName; import com.itextpdf.kernel.pdf.PdfPage; import com.itextpdf.kernel.pdf.canvas.PdfCanvasProcessor; import com.itextpdf.kernel.pdf.canvas.parser.EventType; import com.itextpdf.kernel.pdf.canvas.parser.IEventListener; import com.itextpdf.kernel.pdf.canvas.parser.data.IEventData; import com.itextpdf.kernel.pdf.canvas.parser.data.XObjectDoEvent; import com.itextpdf.kernel.pdf.xobject.PdfImageXObject; import java.util.HashSet; import java.util.Set; public void removeQRCodes(PdfDocument pdfDoc) { for (int i = 1; i <= pdfDoc.getNumberOfPages(); i++) { PdfPage page = pdfDoc.getPage(i); Set<PdfName> qrXObjectNames = new HashSet<>(); // 识别页面中的QR码XObject var resources = page.getResources().getPdfObject(); var xObjects = resources.getAsDictionary(PdfName.XObject); if (xObjects != null) { for (PdfName name : xObjects.keySet()) { var obj = xObjects.get(name); if (obj instanceof com.itextpdf.kernel.pdf.PdfStream stream) { var image = new PdfImageXObject(stream); if (isQRCode(image)) { qrXObjectNames.add(name); } } } } // 修改内容流,移除QR码的绘制指令 if (!qrXObjectNames.isEmpty()) { var newContentStream = new com.itextpdf.kernel.pdf.PdfStream(); var processor = new PdfCanvasProcessor(new IEventListener() { @Override public void eventOccurred(IEventData data, EventType type) { if (type == EventType.XOBJECT_DO) { XObjectDoEvent doEvent = (XObjectDoEvent) data; if (qrXObjectNames.contains(doEvent.getXObjectId())) { // 跳过绘制QR码的指令 return; } } // 将其他指令写入新内容流 data.getCanvas().writeCommandsToStream(newContentStream); } @Override public Set<EventType> getSupportedEvents() { return Set.of(EventType.ALL); } }); processor.processPageContent(page); // 替换原页面内容流 page.put(PdfName.Contents, newContentStream); } } }
关键说明
- 直接清空资源流会导致PDF结构损坏,修改内容流移除绘制指令才是安全的方式。
- 结合ZXing识别QR码能大幅提升准确性,避免误删普通方形图片。
- 处理完成后,记得保存修改后的PdfDocument:
pdfDoc.save(new FileOutputStream("output.pdf"));
内容的提问来源于stack exchange,提问作者Vivek Pandey
相关产品推荐
相关产品推荐

