现在我正在使用iTextSharp从PDF中提取线条和矩形.我使用的方法如下:
PdfReader reader = new PdfReader(strPDFFileName);
var pageSize = reader.GetPageSize(1);
var cropBox = reader.GetCropBox(1);
byte[] pageBytes = reader.GetPageContent(1);
PRTokeniser tokeniser = new PRTokeniser(new(RandomAccessFileOrArray(pageBytes));
PRTokeniser.TokType tokenType;
string tokenValue;
CoordinateCollection cc = new CoordinateCollection();
while (tokeniser.NextToken())
{
tokenType = tokeniser.TokenType;
tokenValue = tokeniser.StringValue;
if (tokenType == PRTokeniser.TokType.OTHER)
{
if (tokenValue == "re")
{
if (buf.Count < 5)
{
continue;
}
float x = float.Parse(buf[buf.Count - 5]);
float y = float.Parse(buf[buf.Count - 4]);
float w = float.Parse(buf[buf.Count - 3]);
float h = float.Parse(buf[buf.Count - 2]);
Coordinate co = new Coordinate();
co.type = "re";
co.X1 = x;
co.Y1 = y;
co.W = w;
co.H = h;
cc.AddCoordinate(co);
}
}
}
Run Code Online (Sandbox Code Playgroud)
代码工作正常.但是我遇到了关于PDF测量单元的问题.来自reader.getPageSize的值是(619*792),这意味着页面大小是691*792,但是当我从tokeniser获得矩形时,x和y总是超过页面大小,它的值总是x = 150,Y = 4200,W = 1500,H = 2000.
我相信reader.getPageSize和tokeniser的测量单位是不同的.
那么请你帮忙告诉我如何转换它们?
作为开始注释:实际提取的是 PDF内容流中重新 操作的坐标参数,它们的值不是特定于iTextSharp的.
要理解为什么矩形的坐标看起来如此偏离页面,你首先必须意识到PDF中使用的坐标系是可变的!
用户空间坐标系统仅被初始化为默认状态,其中页面字典中的CropBox条目指定对应于可见区域的用户空间的矩形.
在页面内容操作的过程中,可以使用cm操作甚至多次转换坐标系.常见的转换是旋转,平移,倾斜和缩放.
在你的情况下,最有可能至少有一个扩展.
您可能希望在PDF规范的第8.3节"坐标系"中学习详细信息.
要检索包含转换的坐标,除了重新操作之外,您还可以找到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) { }
}
Run Code Online (Sandbox Code Playgroud)
并将其应用于这样的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);
}
}
Run Code Online (Sandbox Code Playgroud)
在" 矩形"," 移动到"," 行到 "和" 曲线"之后,您将看到坐标信息而不应用变换,即像您一样检索.
之后- >你会看到相应的变换坐标.
PS此功能仍然是新功能.可能很快就会使用另一种更简单的方法来支持iTextSharp为您捆绑路径信息,而不是简单地一次转发一个路径构建操作.