这与我之前提到的有关reading an annotation's appearance stream and writing its text to the Contents的问题有关。我想用Line注释做一个类似的动作,读取它的外观宽度并设置实际宽度以匹配外观。
我无法弄清楚如何调整“使用外观设置文本内容”功能来设置线宽。这是我目前用于获取文本的代码:
//main function for setting inner content to appearance value
public void changeAnnotationContentToAppearance(PdfDictionary dict)
{
string surface = pdfTextParser.retrieveText(dict);
if (surface != null)
{
//update CONTENTS with appearance
//for changing line width, I would instead modify the /BS dictionary's /W key value, i think
dict.Put(PdfName.CONTENTS, new PdfString(surface));
}
}
//get text from /AP dictionary
public string retrieveText(PdfDictionary annotDictionary)
{
PdfDictionary appearancesDictionary = annotDictionary.GetAsDict(PdfName.AP);
foreach (PdfName key in appearancesDictionary.Keys)
{
PdfStream value = appearancesDictionary.GetAsStream(key);
if (value != null)
{
String text = ExtractAnnotationText(value);
return text;
}
}
return null;
}
//read the appearance stream and extract text contents
public String ExtractAnnotationText(PdfStream xObject)
{
PdfDictionary resources = xObject.GetAsDict(PdfName.RESOURCES);
ITextExtractionStrategy strategy = new LocationTextExtractionStrategy();
PdfContentStreamProcessor processor = new PdfContentStreamProcessor(strategy);
processor.ProcessContent(ContentByteUtils.GetContentBytesFromContentObject(xObject), resources);
return strategy.GetResultantText();
}
ExtractAnnotationText()
似乎只能读取文本,而不能读取行宽,因为ITextExtractionStrategy()
没有任何返回行属性的方法。 iTextSharp是否提供了另一种用于处理线路的提取策略?
如果我正确阅读,this question,this one和this one建议我需要实现一个类,但我不确定我应该为哪个类进行子类化得到行数据,或者我将如何做到这一点。
编辑:我还想获得在文本框中定义矩形的点的外观数据。虽然这可能是一个不同的问题,但它似乎与此问题密切相关:检索定义注释外观流的非文本图形数据。
答案 0 :(得分:2)
您需要PathRenderInfo
对象来获取有关线条和形状的信息。在iText 7中引入了PathRenderInfo
对象。这是我写得很快的概念证明:
public static void main(String args[]) throws IOException {
PdfDocument document = new PdfDocument(new PdfReader(SRC));
PdfPage page = document.getPage(1);
PdfCanvasProcessor processor = new PdfCanvasProcessor(new IEventListener() {
public void eventOccurred(IEventData data, EventType type) {
if (type == EventType.RENDER_PATH) {
PathRenderInfo renderinfo = (PathRenderInfo) data;
int i = renderinfo.getOperation();
switch (i) {
case 1:
System.out.print("Stroke: ");
break;
case 2:
System.out.print("Fill: ");
break;
default:
System.out.print("No: ");
}
for (Subpath p : renderinfo.getPath().getSubpaths()) {
for (IShape shape : p.getSegments()) {
for (Point point : shape.getBasePoints()) {
System.out.println(String.format("x = %s; y = %s", point.getX(), point.getY()));
}
}
}
}
}
public Set<EventType> getSupportedEvents() {
return null;
}
});
processor.processPageContent(page);
}
我在带有大量行的PDF上运行它,这是输出的一部分:
Stroke: x = -406.0; y = -240.0
x = 406.0; y = -240.0
x = -406.0; y = -200.0
x = 406.0; y = -200.0
x = -406.0; y = -160.0
x = 406.0; y = -160.0
x = -406.0; y = -120.0
x = 406.0; y = -120.0
x = -406.0; y = -80.0
x = 406.0; y = -80.0
x = -406.0; y = -40.0
x = 406.0; y = -40.0
x = -406.0; y = 0.0
x = 406.0; y = 0.0
x = -406.0; y = 40.0
x = 406.0; y = 40.0
x = -406.0; y = 80.0
您必须升级到iText 7才能使其发挥作用,您还必须探索PathRenderInfo
,Subpath
和IShape
对象中包含哪些信息。< / p>
<强>更新强>
如评论所示,人们可能想知道你是否提出了正确的问题。看一下这个屏幕截图:
如果您查看此PDF,您将找不到外观流:
外观由观众根据以下值创建:
/C
:颜色:红色= 0,绿色= 0,蓝色= 1(因此线条为蓝色)/LE
:行尾(在本例中为菱形)L
:(x = 20,y = 790)和(x = 575,y = 790)之间的界线如果您在注释词典中掌握了所有必要的信息,为什么要解析外观?
文本注释的矩形也是如此。该信息存储在/Rect
值中。在这种情况下,注释是无量纲的([0 0 0 0]
),因为我们只有一个维度,而行由/L
中存储的值定义。
答案 1 :(得分:2)
OP在评论中澄清了@Bruno的回答
我想解析外观流并使用其值来设置注释字典中的值。
和
当外观流与这些值不匹配时(例如,边框在字典中为黑色但在外观流中为红色),...我想将字典内容设置为外观流。在Foxit中创建然后在Adobe中打开的某些PDF中会出现此问题。
不幸的是,PDF允许很多方法来创建类似的效果。绘制边框,例如,
因此,对于您的问题,一个真正通用的解决方案介于非常复杂和不可能之间。
此外,仅使用注释字典中的有限抽象设置可能无法表示某些外观。例如。外观流中的边框可能在中间创建为实体,但使用透明度左右淡出,或者可能使用颜色着色操作符绘制,从而产生颜色渐变,或者其形状可能不是完全矩形但是不规则,或者,或......
如果您不是在寻找通用解决方案,但仅仅是针对某些软件产品(如Foxit在某些版本中创建)创建的注释的解决方案,以及该软件创建的外观是否可以使用抽象注释字典来表示价值观,任务变得可行。
在这种情况下,您应该首先分析这些软件产品创建的样本外观流。很可能会出现一些模式。
一旦找到该模式,您就可以开始实施匹配的iTextSharp 5.5.x IExtRenderListener
或iTextSharp 7.0.x IEventListener
。