如何使用iText7获取PDF主/子图层名称及图层内元素坐标属性
iText7提取PDF图层及图层内元素属性实现方案
1 递归获取所有图层(含子图层)名称
你原有代码只能拿到顶层图层的原因是getLayers()方法仅返回根层级的图层列表,子图层存储在父图层的getChildren()属性中,需要递归遍历才能获取全量图层:
import com.itextpdf.kernel.pdf.PdfDocument; import com.itextpdf.kernel.pdf.PdfName; import com.itextpdf.kernel.pdf.PdfReader; import com.itextpdf.kernel.pdf.layer.PdfLayer; import java.io.IOException; import java.util.List; public class LayerExtractor { public static void main(String[] args) throws IOException { PdfDocument pdfDoc = new PdfDocument(new PdfReader("你的PDF文件路径")); List<PdfLayer> rootLayers = pdfDoc.getCatalog().getOCProperties(true).getLayers(); // 递归遍历所有图层 for (PdfLayer rootLayer : rootLayers) { parseLayer(rootLayer, 0); } pdfDoc.close(); } private static void parseLayer(PdfLayer layer, int depth) { if (!layer.isOnPanel()) { return; } // 打印当前图层名称,depth用来标识层级 String layerName = layer.getPdfObject().get(PdfName.Name).toString(); System.out.printf("%s%s%n", " ".repeat(depth), layerName); // 递归遍历子图层 List<PdfLayer> children = layer.getChildren(); if (children != null && !children.isEmpty()) { for (PdfLayer child : children) { parseLayer(child, depth + 1); } } } }
2 提取图层内元素的坐标、尺寸属性
你需要通过iText7的画布事件监听机制,遍历页面内容时捕获文本、路径(包含线条、曲线、矩形等)、图片等元素,同时判断元素所属的OCG(可选内容组,对应PDF图层),匹配后提取对应属性:
2.1 实现思路
- 自定义
IEventListener实现类,处理TextRenderInfo(文本元素)、PathRenderInfo(路径类元素)、ImageRenderInfo(图片元素)事件 - 每个渲染信息对象可关联到对应的OCG,即可判断所属图层
- 从渲染信息中提取坐标、尺寸属性,PDF默认坐标原点为页面左下角,可根据需求自行转换为左上角原点
2.2 代码示例
import com.itextpdf.kernel.canvas.PdfCanvasProcessor; import com.itextpdf.kernel.geom.Rectangle; import com.itextpdf.kernel.pdf.PdfDocument; import com.itextpdf.kernel.pdf.PdfPage; import com.itextpdf.kernel.pdf.PdfReader; import com.itextpdf.kernel.pdf.canvas.parser.EventType; import com.itextpdf.kernel.pdf.canvas.parser.data.IEventData; import com.itextpdf.kernel.pdf.canvas.parser.data.PathRenderInfo; import com.itextpdf.kernel.pdf.canvas.parser.data.TextRenderInfo; import com.itextpdf.kernel.pdf.canvas.parser.listener.IEventListener; import com.itextpdf.kernel.pdf.layer.PdfLayer; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; public class LayerElementExtractor implements IEventListener { // 存储图层ID和图层名称的映射 private final Map<Integer, String> layerIdNameMap = new HashMap<>(); public LayerElementExtractor(PdfDocument pdfDoc) { // 预加载所有图层的ID和名称映射 loadLayerMap(pdfDoc.getCatalog().getOCProperties(true).getLayers()); } private void loadLayerMap(List<PdfLayer> layers) { for (PdfLayer layer : layers) { if (layer.isOnPanel()) { layerIdNameMap.put(layer.getPdfObject().getIndirectReference().getObjNumber(), layer.getPdfObject().get(PdfName.Name).toString()); if (layer.getChildren() != null) { loadLayerMap(layer.getChildren()); } } } } @Override public void eventOccurred(IEventData data, EventType type) { Integer layerId = null; // 获取当前元素所属的图层ID if (data instanceof TextRenderInfo textInfo) { layerId = textInfo.getMcid(); } else if (data instanceof PathRenderInfo pathInfo) { layerId = pathInfo.getMcid(); } if (layerId == null || !layerIdNameMap.containsKey(layerId)) { return; } String layerName = layerIdNameMap.get(layerId); // 提取对应元素属性 if (type == EventType.RENDER_TEXT) { TextRenderInfo textInfo = (TextRenderInfo) data; float x = textInfo.getBaseline().getStartPoint().get(0); float y = textInfo.getBaseline().getStartPoint().get(1); float width = textInfo.getBaseline().getEndPoint().get(0) - x; float height = textInfo.getAscentLine().getStartPoint().get(1) - textInfo.getDescentLine().getStartPoint().get(1); String content = textInfo.getText(); System.out.printf("图层[%s] 文本元素:内容=%s, x=%.2f, y=%.2f, 宽=%.2f, 高=%.2f%n", layerName, content, x, y, width, height); } else if (type == EventType.RENDER_PATH) { PathRenderInfo pathInfo = (PathRenderInfo) data; Rectangle bbox = pathInfo.getPath().getBounds(); float x = bbox.getX(); float y = bbox.getY(); float width = bbox.getWidth(); float height = bbox.getHeight(); System.out.printf("图层[%s] 路径元素:x=%.2f, y=%.2f, 宽=%.2f, 高=%.2f%n", layerName, x, y, width, height); } } @Override public Set<EventType> getSupportedEvents() { return Set.of(EventType.RENDER_TEXT, EventType.RENDER_PATH, EventType.RENDER_IMAGE); } public static void main(String[] args) throws IOException { PdfDocument pdfDoc = new PdfDocument(new PdfReader("你的PDF文件路径")); LayerElementExtractor extractor = new LayerElementExtractor(pdfDoc); // 遍历所有页面提取元素 for (int i = 1; i <= pdfDoc.getNumberOfPages(); i++) { PdfPage page = pdfDoc.getPage(i); PdfCanvasProcessor processor = new PdfCanvasProcessor(extractor); processor.processPageContent(page); } pdfDoc.close(); } }
内容的提问来源于stack exchange,提问作者Sheng Yu
相关产品推荐
相关产品推荐

