我正在尝试为一位拥有工作室的朋友创建一个小型应用程序。我将其作为一个小项目开始,也是为了提高我的 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;
}
}
好的,有了我身边的实际测试文件,我查看了你的代码。
乍一看我发现了以下问题
您不完全覆盖
processOperator
。如果您覆盖它,则必须处理所有感兴趣的运算符。一般来说,更好的方法是注册运算符类并让 PDFGraphicsStreamEngine
使用原始 processOperator
代码完成其工作。
对于您的示例文件,您没有处理其中用于构建路径的所有运算符,您忘记了 v 和 y 运算符。
对于一般情况,您还可以忽略当前的变换矩阵,该矩阵可能会被 cm 和 Q 调用更改。另外,您还忽略了 re 运算符。
你的
bezierLength
方法不可能正确,因为它只使用了两个控制点和终点的坐标,而完全忽略了起点。
你的
getPageUnits
和getUnitsPerPoint
对我来说根本没有意义。对于普通 PDF,getUnitsPerPoint
将始终返回百分之几甚至千的值,因此您的 getPageUnits
将始终返回“毫米”。但这些文件几乎没有以毫米为单位。