java - 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)的以下结果
我无法弄清楚我做错了什么。有任何想法吗?
解决方案
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 部分:PDF 1.7、PDF 32000-1:2008,第 8.3 节:坐标系,第 115 页
推荐阅读
- python - Python 3 TypeError:并非所有参数都在字符串格式化期间转换,列出问题
- objective-c - Xcode 10 错误 PrefixHeader.pch.gch' 不是有效的预编译 PCH 文件
- internals - Reasonml 地图不纯?
- php - 使用codeigniter框架时如何在cpanel中安装composer?
- workbox - 如何使用 workbox.streams 修复服务工作者中的 fetch 事件
- mongodb - 如何在 mongoDB 中处理 $project 中的多个 $lookup 和大量列
- jquery - 如何使用 jquery 在下拉选择更改时显示/隐藏标签
- google-app-engine - 如何设置 GCP App Engine 服务的服务名称
- go - 谷歌云函数(Golang)和 Terraform
- amazon-web-services - 如何在 Cloudflare 中的另一个 ec2 实例 AWS 上添加子域?