如何使用iTextSharp读取Line注释的外观宽度?

时间:2016-05-18 23:48:37

标签: c# pdf itextsharp itext

这与我之前提到的有关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 questionthis onethis one建议我需要实现一个类,但我不确定我应该为哪个类进行子类化得到行数据,或者我将如何做到这一点。

编辑:我还想获得在文本框中定义矩形的点的外观数据。虽然这可能是一个不同的问题,但它似乎与此问题密切相关:检索定义注释外观流的非文本图形数据。

2 个答案:

答案 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才能使其发挥作用,您还必须探索PathRenderInfoSubpathIShape对象中包含哪些信息。< / p>

<强>更新

如评论所示,人们可能想知道你是否提出了正确的问题。看一下这个屏幕截图:

enter image description here

如果您查看此PDF,您将找不到外观流:

enter image description here

外观由观众根据以下值创建:

  • /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