需要帮助计算pdf中线条路径的总长度

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

我正在尝试为一位拥有工作室的朋友创建一个小型应用程序。我将其作为一个小项目开始,也是为了提高我的 Java 知识。

现在我在研究后做了一些计算。 问题是计算没有输出正确的数字,我不确定如何进一步进行或在哪里可以找到更多信息来微调计算。

我正在使用 Apache PDFBox 我的 pdf 正在检查洋红色线条

所以我的问题如下,任何人都可以给我更多信息或帮助我正确计算吗?现在我的pdf应该返回:3017,789mm,但其洋红色路径的长度:7371.512237553014

我不想显示它或任何东西,我只需要信息

这是我到目前为止的代码:

public class PdfCalculatorUtil extends PDFGraphicsStreamEngine {
    private double totalLength = 0;
    private Point2D.Double currentPoint = new Point2D.Double();
    private Point2D.Double startPoint = new Point2D.Double();
    private boolean inMagentaPath = false;

    public PdfCalculatorUtil(PDPage page) {
        super(page);
    }

    @Override
    public void appendRectangle(Point2D p0, Point2D p1, Point2D p2, Point2D p3) {
    }

    @Override
    public void drawImage(PDImage pdImage) {
    }

    @Override
    public void clip(int windingRule) {
    }

    @Override
    public void moveTo(float x, float y) {
        currentPoint.setLocation(x, y);
        startPoint.setLocation(x, y);
    }

    @Override
    public void lineTo(float x, float y) {
        totalLength += currentPoint.distance(x, y);
        currentPoint.setLocation(x, y);
    }

    @Override
    public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) {
        // Calculate the length of the Bézier curve segment
        totalLength += bezierLength(x1, y1, x2, y2, x3, y3);
        currentPoint.setLocation(x3, y3); // Update the current point
    }

    @Override
    public Point2D getCurrentPoint() {
        return currentPoint;
    }

    @Override
    public void closePath() {
        totalLength += currentPoint.distance(startPoint);
        currentPoint.setLocation(startPoint);
    }

    @Override
    public void endPath() {
    }

    @Override
    public void strokePath() {
    }

    @Override
    public void fillPath(int windingRule) {
    }

    @Override
    public void fillAndStrokePath(int windingRule) {
    }

    @Override
    public void shadingFill(COSName shadingName) {
    }

    public double getTotalLength() {
        return totalLength;
    }

    public void extractPathLengths(PDDocument document) throws IOException {
        for (PDPage page : document.getPages()) {
            processPage(page);
        }
    }

    private PDRectangle getPageDimensions(PDPage page) {
        return page.getMediaBox();
    }

    private double getUnitsPerPoint(PDPage page) {
        PDRectangle mediaBox = getPageDimensions(page);
        // Calculate the length of the diagonal of the media box
        double diagonalLength = Math.sqrt(Math.pow(mediaBox.getWidth(), 2) + Math.pow(mediaBox.getHeight(), 2));
        // Get the diagonal length in points
        return diagonalLength / Math.sqrt(2);
    }

    private String getPageUnits(PDPage page) {
        double unitsPerPoint = getUnitsPerPoint(page);
        // Determine the units
        if (unitsPerPoint >= 25.4) {
            return "millimeters";
        } else if (unitsPerPoint >= 2.54) {
            return "centimeters";
        } else {
            return "points";
        }
    }

    public void checkPdfUnits(PDDocument document) {
        for (PDPage page : document.getPages()) {
            String units = getPageUnits(page);
            System.out.println("Page Units: " + units);
        }
    }

    @Override
    public void processOperator(Operator operator, List<COSBase> operands) {
        String operation = operator.getName();
        if ("m".equals(operation)) {
            if (inMagentaPath) {
                float x = ((COSNumber) operands.get(0)).floatValue();
                float y = ((COSNumber) operands.get(1)).floatValue();
                moveTo(x, y);
                System.out.println("Move to (magenta): (" + x + ", " + y + ")");
            }
        } else if ("l".equals(operation)) {
            if (inMagentaPath) {
                float x = ((COSNumber) operands.get(0)).floatValue();
                float y = ((COSNumber) operands.get(1)).floatValue();
                lineTo(x, y);
                System.out.println("Line To (magenta): (" + x + ", " + y + ")");
            }
        } else if ("h".equals(operation)) {
            closePath();
        } else if ("c".equals(operation)) {
            if (inMagentaPath) {
            float x1 = ((COSNumber) operands.get(0)).floatValue();
            float y1 = ((COSNumber) operands.get(1)).floatValue();
            float x2 = ((COSNumber) operands.get(2)).floatValue();
            float y2 = ((COSNumber) operands.get(3)).floatValue();
            float x3 = ((COSNumber) operands.get(4)).floatValue();
            float y3 = ((COSNumber) operands.get(5)).floatValue();
            double segmentLength = bezierLength(x1, y1, x2, y2, x3, y3);
            curveTo(x1, y1, x2, y2, x3, y3);
            System.out.println("Bezier Segment Length (magenta): " + segmentLength);
            }
        } else if ("K".equals(operation)) {
            // Set CMYK color
            float c = ((COSNumber) operands.get(0)).floatValue();
            float m = ((COSNumber) operands.get(1)).floatValue();
            float y = ((COSNumber) operands.get(2)).floatValue();
            float k = ((COSNumber) operands.get(3)).floatValue();
            // Check for magenta color
            inMagentaPath = c == 0.0 && m == 1.0 && y == 0.0 && k == 0.0;
        }
    }

    private double bezierLength(double x1, double y1, double x2, double y2, double x3, double y3) {
        double ax = 3 * x1 + 3 * x2 - x3;
        double ay = 3 * y1 + 3 * y2 - y3;
        double bx = 3 * x1 - 3 * x2 + 3 * x3;
        double by = 3 * y1 - 3 * y2 + 3 * y3;
        double cx = 3 * x2 - 3 * x3;
        double cy = 3 * y2 - 3 * y3;
        double integral = 0;
        int nt = 100; // Increase the number of intervals for better accuracy
        double dt = 1.0 / nt;
        for (int i = 0; i < nt; i++) {
            double t2 = Math.pow(i * dt, 2);
            double t3 = Math.pow(i * dt, 3);
            double sqrtTerm = Math.sqrt(ax * t2 + bx * t3 + cx);
            double sqrtTermY = Math.sqrt(ay * t2 + by * t3 + cy);
            if (!Double.isNaN(sqrtTerm) && !Double.isInfinite(sqrtTerm) &&
                    !Double.isNaN(sqrtTermY) && !Double.isInfinite(sqrtTermY)) {
                integral += Math.sqrt(sqrtTerm * sqrtTerm + sqrtTermY * sqrtTermY) * dt;
            }
        }
        return integral;
    }
}

java spring pdfbox
1个回答
0
投票

好的,有了我身边的实际测试文件,我查看了你的代码。

乍一看我发现了以下问题

  • 您不完全覆盖

    processOperator
    。如果您覆盖它,则必须处理所有感兴趣的运算符。一般来说,更好的方法是注册运算符类并让
    PDFGraphicsStreamEngine
    使用原始
    processOperator
    代码完成其工作。

    对于您的示例文件,您没有处理其中用于构建路径的所有运算符,您忘记了 vy 运算符。

    对于一般情况,您还可以忽略当前的变换矩阵,该矩阵可能会被 cmQ 调用更改。另外,您还忽略了 re 运算符。

  • 你的

    bezierLength
    方法不可能正确,因为它只使用了两个控制点和终点的坐标,而完全忽略了起点。

  • 你的

    getPageUnits
    getUnitsPerPoint
    对我来说根本没有意义。对于普通 PDF,
    getUnitsPerPoint
    将始终返回百分之几甚至千的值,因此您的
    getPageUnits
    将始终返回“毫米”。但这些文件几乎没有以毫米为单位。

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