首页 > 解决方案 > TextPosition 边界框 PDFBox

问题描述

我正在尝试从 TextPosition 绘制相应的字形边界框,如 PDF 32000 文档中所示。 在此处输入图像描述

这是我的函数,它执行从字形空间用户空间的计算

@Override 
protected void processTextPosition(TextPosition text) {
    PDFont font = pos.getFont();
    
    BoundingBox bbox = font.getBoundingBox();
    
    Rectangle2D.Float rect = new Rectangle2D.Float(bbox.getLowerLeftX(), bbox.getUpperRightY(), 
            bbox.getWidth(), bbox.getHeight());
    
    AffineTransform at = pos.getTextMatrix().createAffineTransform();
    
    if (font instanceof PDType3Font) {
        at.concatenate(font.getFontMatrix().createAffineTransform());
    } else {
        at.scale(1 / 1000f, 1 / 1000f);
    }
    Shape shape = at.createTransformedShape(rect);
    rectangles.add(fillBBox(text));
    
            
    super.processTextPosition(text);
}

这是绘制提取的矩形的函数:

private void drawBoundingBoxes() throws IOException {
    
    String fileNameOut = path.substring(0, path.lastIndexOf(".")) + "_OUT.pdf";
    log.info("Drawing Bounding Boxes for TextPositions");
    
    PDPageContentStream contentStream = new PDPageContentStream(document, 
            document.getPage(document.getNumberOfPages()-1),
            PDPageContentStream.AppendMode.APPEND, false , true );
    contentStream.setLineWidth(1f);
    contentStream.setStrokingColor(Color.RED);
    
    try{
        for (Shape p : rectangles) {
            p = all.get(0);
        double[] coords = new double[6];
        GeneralPath g = new GeneralPath(p.getBounds2D());
        for (PathIterator pi = g.getPathIterator(null);
             !pi.isDone();
             pi.next()) {
            System.out.println(Arrays.toString(coords));
            switch (pi.currentSegment(coords)) {
            case PathIterator.SEG_MOVETO:
                System.out.println("move to");
                contentStream.moveTo ((float)coords[0], (float) coords[1]);
                break;
                
            case PathIterator.SEG_LINETO:
                System.out.println("line to");
                contentStream.lineTo ((float)coords[0], (float) coords[1]);
                break;
                
            case PathIterator.SEG_CUBICTO:
                System.out.println("cubc to");
                contentStream.curveTo((float)coords[0], (float) coords[1],
                        (float)coords[2], (float) coords[3], 
                        (float)coords[4],(float) coords[5]);
                break;
                
            case PathIterator.SEG_CLOSE:
                System.out.println("close");
                contentStream.closeAndStroke();
                break;
            default:
                System.out.println("no shatt");
                break;
            }
            
        }
    
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        contentStream.close();
        document.save(new File(fileNameOut));
    }
}

然后,当我尝试在 pdf 上绘图时,我得到第一个字母(大写 V)的以下结果 在此处输入图像描述

我无法弄清楚我做错了什么。有任何想法吗?

标签: javapdfpdf-generationpdfbox

解决方案


D先生,

我测试了你的代码,我需要做的唯一改变就是反转 Y 轴。之所以需要这样做是因为PDF 用户空间的原点位于左下角,与Java 2D 用户空间的原点位于左上角[1]不同。

8.3.2.3 用户空间

用户空间坐标系应初始化为文档每一页的默认状态。页面字典中的CropBox条目应指定与预期输出介质(显示窗口或打印页面)的可见区域相对应的用户空间矩形。正 x 轴水平向右延伸,正 y 轴垂直向上延伸,如在标准数学实践中一样(受页面字典中的Rotate条目的更改)。沿 x 轴和 y 轴的单位长度由页面字典中的UserUnit条目 (PDF 1.6) 设置(参见表 30)。如果该条目不存在或不支持,则使用默认值 1⁄72 英寸。该坐标系称为默认用户空间。[2]

源代码

@Override 
protected void processTextPosition(TextPosition text) {
    try {
        PDFont font = pos.getFont();

        BoundingBox bbox = font.getBoundingBox();

        Rectangle2D.Float rect = new Rectangle2D.Float(bbox.getLowerLeftX(), bbox.getUpperRightY(),
                    bbox.getWidth(), bbox.getHeight());

        AffineTransform at = pos.getTextMatrix().createAffineTransform();

        if (font instanceof PDType3Font) {
            at.concatenate(font.getFontMatrix().createAffineTransform());
        } else {
            at.scale(1 / 1000f, 1 / 1000f);
        }

        Shape shape = at.createTransformedShape(rect);

        // Invert Y axis
        Rectangle2D bounds = shape.getBounds2D();
        bounds.setRect(bounds.getX(), bounds.getY() - bounds.getHeight(), bounds.getWidth(), bounds.getHeight());

        rectangles.add(bounds);

        super.processTextPosition(text);

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

参考

  1. Java 2D API 概念:坐标

  2. 文档管理 - 便携式文档格式 - 第 1 部分:PDF 1.7、PDF 32000-1:2008,第 8.3 节:坐标系,第 115 页


推荐阅读