如何使用TallComponents PDFKit获取PDF中形状的绝对位置
本文关键字:位置 TallComponents 何使用 PDFKit 获取 PDF | 更新日期: 2023-09-27 18:25:59
我正试图使用TallComponents PDFKit 4来识别PDF中特定形状的位置,这样我就可以相对于它们定位其他形状。(即,识别图像下方10 pt,右侧40 pt)
PDFKit中的每个Shape
都具有X
和Y
坐标属性,但坐标系的原点似乎会根据嵌套的形状而变化。
以下代码将第一页上的所有图形提取为形状:
Stream stream;
... // initialize stream
Document document = new Document(stream);
ShapeCollection shapes = document.Pages[0].CreateShapes();
集合中的形状都继承自类ContentShape
。专业包括Textshape
、FreeHandShape
、ImagesShape
和ShapeCollection
。后者允许嵌套。每个形状的坐标系由包含的ShapeCollection
的坐标系乘以其自身的ContentShape.Transform
属性来定义。
因此,为了计算绝对坐标(或设备坐标),您需要将从根到实际形状的所有变换连接起来。
以下代码将路径的坐标写入输出:
Matrix transform = new Matrix(); // start with identity
write(shapes, transform);
void write(Shape shape, Matrix transform)
{
if (shape is TallComponents.PDF.Shapes.ContentShape)
{
ContentShape contentshape = (ContentShape)shape;
// calculate the transformation matrix of the user space
Matrix newTransform = contentshape.Transform.CreateGdiMatrix();
newTransform.Multiply(transform, MatrixOrder.Append);
if (shape is FreeHandShape)
{
write((FreeHandShape)shape, newTransform);
}
else if (shape is ImageShape)
{
write((ImageShape)shape, newTransform);
}
else if (shape is ShapeCollection)
{
// recurse
ShapeCollection shapes = (ShapeCollection)shape;
foreach (Shape s in shapes)
write(s, newTransform);
}
// ignore other shapes
}
}
以下方法使用绝对坐标以类似SVG的格式将FreeHandShape的所有点写入输出:
void write(FreeHandShape freeHandShape, Matrix transform)
{
write(freeHandShape.Paths, transform);
}
void write(FreeHandPathCollection paths, Matrix transform)
{
foreach (var path in paths)
write(path, transform);
}
void write(FreeHandPath path, Matrix transform)
{
foreach (var segment in path.Segments)
{
if (segment is FreeHandStartSegment)
{
var s = (FreeHandStartSegment)segment;
Console.Write("M {0} ", write(s.X, s.Y, transform));
}
else if (segment is FreeHandLineSegment)
{
var s = (FreeHandLineSegment)segment;
Console.Write("L {0} ", write(s.X1, s.Y1, transform));
}
else if (segment is FreeHandBezierSegment)
{
var s = (FreeHandBezierSegment)segment;
Console.Write("C {0} {1} {2} ",
write(s.X1, s.Y1, transform),
write(s.X2, s.Y2, transform),
write(s.X3, s.Y3, transform));
}
}
if (path.Closed)
Console.Write("Z ");
}
}
string write(double x, double y, Matrix transform)
{
PointF[] points = { new PointF((float)x, (float)y) };
transform.TransformPoints(points);
return String.Format("{0} {1}", points[0].X, points[0].Y);
}
更新:
以下方法使用绝对坐标以类似SVG的格式将ImageShape写入输出。请注意,它将图像绘制为红色矩形,因为它只显示角的位置。还要注意,它将(0, 0)
转换为左下角,而不是(X, Y)
。原因是属性ContentShape.X
和ContentShape.Y
是只读属性,它们返回转换后的位置。因此,如果我们也对(X, Y)
进行变换,它将被变换两次。
private void writeImageShape(ImageShape image, Matrix transform)
{
Console.Write("M {0} ", writePoint(0, 0, transform));
Console.Write("L {0} ", writePoint(0, image.Height, transform));
Console.Write("L {0} ", writePoint(image.Width, image.Height, transform));
Console.Write("L {0} ", writePoint(image.Width, 0, transform));
Console.Write("Z");
}
为了简化起见,此代码不考虑定义初始转换的页面的"旋转"answers"裁剪框"属性。下面是一个工作代码示例,它使用绝对(设备)坐标将所有路径和图像(作为矩形)转换为SVG。