首先说明:你提取的实际上是在PDF内容流中 re 操作的坐标参数,它们的值是不是 iTextSharp 特定。
你得到的价值
要理解为什么矩形的坐标看起来如此离页,您首先必须意识到 PDF 中使用的坐标系是可变的!
用户空间坐标系只是初始化到默认状态,在该状态下页面字典中的CropBox条目指定用户的矩形可见区域对应的空间。
在页面内容操作的过程中,坐标系可能会被变换,甚至多次,使用cm操作。常见的变换是旋转、平移、倾斜和缩放。
在您的情况下,很可能至少有一个缩放。
您可能想在PDF specification 的第 8.3 节“坐标系”中学习详细信息。
如何提取包括变换在内的位置
要检索包括变换在内的坐标,除了 re 操作之外,您还可以找到 cm 操作。此外,您必须找到 q 和 Q 操作(保存和恢复图形状态,包括当前的变换矩阵)。
幸运的是,iTextSharp 的解析器命名空间类可以为您完成大部分繁重的工作,因为 5.5.6 版它们还支持矢量图形。您只需要实现IExtRenderListener 并使用实例解析内容。
例如要在控制台上输出矢量图形信息,可以使用如下实现:
class VectorGraphicsListener : IExtRenderListener
{
public void ModifyPath(PathConstructionRenderInfo renderInfo)
{
if (renderInfo.Operation == PathConstructionRenderInfo.RECT)
{
float x = renderInfo.SegmentData[0];
float y = renderInfo.SegmentData[1];
float w = renderInfo.SegmentData[2];
float h = renderInfo.SegmentData[3];
Vector a = new Vector(x, y, 1).Cross(renderInfo.Ctm);
Vector b = new Vector(x + w, y, 1).Cross(renderInfo.Ctm);
Vector c = new Vector(x + w, y + h, 1).Cross(renderInfo.Ctm);
Vector d = new Vector(x, y + h, 1).Cross(renderInfo.Ctm);
Console.Out.WriteLine("Rectangle at ({0}, {1}) with size ({2}, {3})", x, y, w, h);
Console.Out.WriteLine("--> at ({0}, {1}) ({2}, {3}) ({4}, {5}) ({6}, {7})", a[Vector.I1], a[Vector.I2], b[Vector.I1], b[Vector.I2], c[Vector.I1], c[Vector.I2], d[Vector.I1], d[Vector.I2]);
}
else
{
switch (renderInfo.Operation)
{
case PathConstructionRenderInfo.MOVETO:
Console.Out.Write("Move to");
break;
case PathConstructionRenderInfo.LINETO:
Console.Out.Write("Line to");
break;
case PathConstructionRenderInfo.CLOSE:
Console.Out.WriteLine("Close");
return;
default:
Console.Out.Write("Curve along");
break;
}
List<Vector> points = new List<Vector>();
for (int i = 0; i < renderInfo.SegmentData.Count - 1; i += 2)
{
float x = renderInfo.SegmentData[i];
float y = renderInfo.SegmentData[i + 1];
Console.Out.Write(" ({0}, {1})", x, y);
Vector a = new Vector(x, y, 1).Cross(renderInfo.Ctm);
points.Add(a);
}
Console.Out.WriteLine();
Console.Out.Write("--> at ");
foreach (Vector point in points)
{
Console.Out.Write(" ({0}, {1})", point[Vector.I1], point[Vector.I2]);
}
Console.Out.WriteLine();
}
}
public void ClipPath(int rule)
{
Console.Out.WriteLine("Clip");
}
public iTextSharp.text.pdf.parser.Path RenderPath(PathPaintingRenderInfo renderInfo)
{
switch (renderInfo.Operation)
{
case PathPaintingRenderInfo.FILL:
Console.Out.WriteLine("Fill");
break;
case PathPaintingRenderInfo.STROKE:
Console.Out.WriteLine("Stroke");
break;
case PathPaintingRenderInfo.STROKE + PathPaintingRenderInfo.FILL:
Console.Out.WriteLine("Stroke and fill");
break;
case PathPaintingRenderInfo.NO_OP:
Console.Out.WriteLine("Drop");
break;
}
return null;
}
public void BeginTextBlock() { }
public void EndTextBlock() { }
public void RenderImage(ImageRenderInfo renderInfo) { }
public void RenderText(TextRenderInfo renderInfo) { }
}
并将其应用到这样的 PDF 中:
using (var pdfReader = new PdfReader(....))
{
// Loop through each page of the document
for (var page = 1; page <= pdfReader.NumberOfPages; page++)
{
VectorGraphicsListener listener = new VectorGraphicsListener();
PdfReaderContentParser parser = new PdfReaderContentParser(pdfReader);
parser.ProcessContent(page, listener);
}
}
在矩形、移动到、直线到和沿曲线之后,您会看到坐标不应用转换的信息,即像您一样检索。
-->之后你会看到对应的变换坐标。
PS这个功能还是新的。可能很快就会通过使用另一种更简单的方法来支持它,在该方法中,iTextSharp 为您捆绑路径信息,而不是简单地一次转发每个路径构建操作。