使用iText为横版PDF添加批注:坐标错位问题求助
解决横版显示但MediaBox竖版+旋转270度的PDF批注错位问题
首先可以明确:这个PDF本身没有创建问题——PDF规范允许通过Rotate属性指定页面显示时的旋转角度,MediaBox定义的是页面原始尺寸,两者结合实现横版显示是完全合规的。你遇到的批注错位,本质是坐标坐标系不匹配的问题,完全可以用iText解决。
核心思路:坐标转换
你的批注坐标是基于显示时的横版坐标系(1224x729),但PDF内部的批注坐标是基于MediaBox的原始竖版坐标系(729x1224),再加上270度的旋转,导致两者错位。解决的关键是把显示坐标系的坐标转换为MediaBox坐标系下的正确坐标。
iText具体实现步骤
获取页面关键参数:先拿到页面的旋转角度、MediaBox原始尺寸,以及显示时的页面尺寸:
PdfDocument pdfDoc = new PdfDocument(new PdfReader("input.pdf"), new PdfWriter("output.pdf")); PdfPage page = pdfDoc.getPage(1); // 假设处理第一页 int rotation = page.getRotation(); // 这里会得到270 Rectangle mediaBox = page.getMediaBox(); // 729x1224 Rectangle displaySize = page.getPageSizeWithRotation(); // 1224x729,即显示时的尺寸针对270度旋转做坐标转换
当页面旋转270度时,显示坐标系和MediaBox坐标系的映射关系如下:- 显示坐标系的x轴(向右)对应MediaBox坐标系的y轴(向上)
- 显示坐标系的y轴(向上)对应MediaBox坐标系的x轴(向左),需要反向计算
- 批注的宽高也会因为旋转互换
假设你原本的批注矩形是基于显示坐标系的
Rectangle originalRect = new Rectangle(x, y, w, h);,转换代码如下:// 转换坐标到MediaBox坐标系 float transformedX = originalRect.getY(); float transformedY = mediaBox.getWidth() - originalRect.getX() - originalRect.getWidth(); // 旋转后宽高互换 float transformedW = originalRect.getHeight(); float transformedH = originalRect.getWidth(); Rectangle transformedRect = new Rectangle(transformedX, transformedY, transformedW, transformedH);添加转换后的批注
用转换后的矩形创建并添加批注即可,比如添加文本批注:PdfTextAnnotation annotation = new PdfTextAnnotation(transformedRect) .setTitle(new PdfString("批注")) .setContents("这是转换后的正确批注"); page.addAnnotation(annotation); pdfDoc.close();
通用适配(支持所有旋转角度)
如果你的代码需要处理任意旋转角度(90/180/270度),可以用iText的Matrix类来做通用变换,避免硬编码逻辑:
// 创建旋转对应的变换矩阵,然后取逆矩阵(因为要从显示坐标转回原始坐标) Matrix rotationMatrix = new Matrix().rotate(rotation); Matrix inverseMatrix = rotationMatrix.createInverse(); // 将原始批注矩形的四个点做逆变换 float[] rectPoints = { originalRect.getX(), originalRect.getY(), originalRect.getX() + originalRect.getWidth(), originalRect.getY(), originalRect.getX(), originalRect.getY() + originalRect.getHeight(), originalRect.getX() + originalRect.getWidth(), originalRect.getY() + originalRect.getHeight() }; inverseMatrix.applyTo(rectPoints); // 计算变换后的矩形边界 float minX = Float.MAX_VALUE, minY = Float.MAX_VALUE; float maxX = Float.MIN_VALUE, maxY = Float.MIN_VALUE; for (int i = 0; i < rectPoints.length; i += 2) { minX = Math.min(minX, rectPoints[i]); minY = Math.min(minY, rectPoints[i+1]); maxX = Math.max(maxX, rectPoints[i]); maxY = Math.max(maxY, rectPoints[i+1]); } Rectangle transformedRect = new Rectangle(minX, minY, maxX - minX, maxY - minY);
这样不管页面是哪种旋转角度,都能正确转换坐标,避免批注错位。
内容的提问来源于stack exchange,提问作者chitgoks
相关产品推荐
相关产品推荐

