使用 PDFBox 确定图像定位时出现问题

问题描述 投票:0回答:1

背景:

我有两张图像旋转 90 度(逆时针)并转换为 PDF。我使用了两种不同的工具来转换图像:

  • 文档A:Mac预览
  • 文档B:ImageMagick

从视觉上看,使用 PDF 客户端时文档看起来完全相同。

问题:

我需要找到图像相对于PDF页面的位置信息。我的代码正确识别了一个文档的位置,但对另一个文档的定位是错误的:

  • 文档A:矩形[x=792.0,y=0.0,w=614.4000244140625,h=792.0]
  • 文档B:矩形[x=0.0,y=0.0,w=792.0,h=614.4000244140625]

可视化矩形信息,您可以看到文档 A(红色)没有旋转并且在 x 轴上超出太多:

详情:

使用PDFBox调试器,我可以看到文档A的图像通过CM操作旋转:

q
Q
q
  /Perceptual ri
  q
    0 614.4 -792 0 792 0 cm
    /Im1 Do
  Q
Q

看来我没有正确考虑轮换。

代码:

Matrix matrix = getGraphicsState().getCurrentTransformationMatrix();
Rectangle2D.Double rectangle = new Rectangle2D.Double(
        matrix.getTranslateX(),
        matrix.getTranslateY(),
        matrix.getScalingFactorX(),
        matrix.getScalingFactorY()
);

尝试的解决方案

现在我可以从矩阵中获取旋转度数了:

    protected int getRotation() {
        Matrix matrix = getGraphicsState().getCurrentTransformationMatrix();
        double rotationRadians = -Math.atan2(matrix.getShearY(), matrix.getScaleY());
        return (int) Math.toDegrees(rotationRadians);
    }

然后旋转矩形:

    public Rectangle2D.Double rotate(Rectangle2D rectangle, int rotationDegrees) {
        double x = rectangle.getX() + rectangle.getWidth();
        double y = rectangle.getY();
        
        AffineTransform rotationTransform = new AffineTransform();
        rotationTransform.rotate(Math.toRadians(rotationDegrees), x, y);
        Shape rotatedRectangle = rotationTransform.createTransformedShape(rectangle);
        Rectangle2D bounds = rotatedRectangle.getBounds2D();
        return (Rectangle2D.Double) bounds;
    }

现在它的方向正确(绿色矩形),但需要滑过去:

我可以通过减去原始宽度和旋转宽度的总和来调整新矩形的 x 位置。感觉也许我可能会开始进入脆弱的领域。我也觉得我可能开始重新发明轮子了。

有没有更好的方法来解决这个问题?

更新:

经过进一步测试,该方案还需要对其他角度进行调整。我已经处理过 90、180、270。值得庆幸的是,我们通常不会遇到奇怪的角度,但当我们遇到奇怪的角度时,我有点担心。

java pdf pdfbox
1个回答
0
投票

在评论中您提到4个角的坐标将是您所需要的一切

您可以通过遍历页面内容流指令来提取 PDF 中使用的位图图像的默认用户空间坐标,并在找到位图图像绘制指令时,将当时的“当前变换矩阵”应用到单位正方形的角上, (0, 0)、(0, 1)、(1, 0) 和 (1, 1)。 您可以使用专门的

PDFStreamEngine

来实现,如下所示:

public class UserSpaceCoordinatesPrinter extends PrintImageLocations {
    public UserSpaceCoordinatesPrinter() throws IOException {
        super();
    }

    @Override
    protected void processOperator(Operator operator, List<COSBase> operands) throws IOException {
        String operation = operator.getName();
        if (OperatorName.DRAW_OBJECT.equals(operation)) {
            COSName objectName = (COSName) operands.get(0);
            PDXObject xobject = getResources().getXObject(objectName);
            if (xobject instanceof PDImageXObject) {
                System.out.println("\nFound image [" + objectName.getName() + "]");
                Matrix ctm = getGraphicsState().getCurrentTransformationMatrix();
                System.out.print("Corner coordinates in user space:");
                for (Vector corner : UNIT_SQUARE_CORNERS) {
                    System.out.print(" " + ctm.transform(corner));
                }
                System.out.println();
            } else if(xobject instanceof PDFormXObject) {
                PDFormXObject form = (PDFormXObject)xobject;
                showForm(form);
            }
        } else {
            super.processOperator(operator, operands);
        }
    }

    public static void print(PDDocument document) throws IOException {
        UserSpaceCoordinatesPrinter printer = new UserSpaceCoordinatesPrinter();
        int pageNum = 0;
        for (PDPage page : document.getPages()) {
            pageNum++;
            System.out.println("\n\nProcessing page: " + pageNum);
            System.out.println("Media box: " + page.getMediaBox());
            System.out.println("Page rotation: " + page.getRotation());
            printer.processPage(page);
        }
    }

    final static List<Vector> UNIT_SQUARE_CORNERS = List.of(
            new Vector(0, 0), new Vector(0, 1), new Vector(1, 0), new Vector(1, 1));
}

PrintImageCornerCooperatives实用程序类) 你可以这样使用它:

try (PDDocument document = Loader.loadPDF(PDF_SOURCE)) { UserSpaceCoordinatesPrinter.print(document); }

打印图像角坐标测试testUserCoordinatesInput


    

© www.soinside.com 2019 - 2024. All rights reserved.