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

How to read width of Line annotation's appearance using iTextSharp?

这与我之前提出的关于 的问题有关。我想对 Line 注释执行类似的操作,读取其外观宽度并设置实际宽度以匹配外观。

我无法弄清楚如何调整我的 "set text contents using appearance" 函数来设置线宽。这是我目前用于获取文本的代码:

//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, and this one 建议我需要实现一个 class,但我不确定我应该用哪个子 class 来获得线路数据,或者我将如何去做。

编辑:我还想获取在文本框中定义矩形的点的外观数据。虽然这可能是一个不同的问题,但它似乎与这个问题密切相关:retrieving non-text graphical data defining an annotation's appearance stream。

您需要 PathRenderInfo 对象来获取有关线条和形状的信息。 PathRenderInfo 对象是在 iText 7 中引入的。这是我很快写的概念证明:

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 对象中包含哪些信息.

更新:

如评论中所述,有人可能想知道您是否在问正确的问题。看看这个屏幕截图:

如果您仔细查看此 PDF,您将找不到一个吸引人的地方运行ce 流:

外观运行ce 是由查看者根据以下值创建的:

  • /C:颜色:红色 = 0,绿色 = 0,蓝色 = 1(因此线为蓝色)
  • /LE:线尾(本例中为菱形)
  • L: (x = 20, y = 790) 和 (x = 575, y = 790)
  • ...

如果您在注释词典中掌握了所有必要的信息,为什么还要解析外观运行ce?

文本注释的矩形也是如此。该信息存储在 /Rect 值中。在这种情况下,注释是无量纲的 ([0 0 0 0]),因为我们只有一个维度,并且线条由存储在 /L.

中的值定义

OP 在对@Bruno 的回答的评论中进行了澄清

I want to parse the appearance stream and use its values to set values in the annotation dictionary.

when the appearance stream does not match these values (e.g. the border is black in the dictionary but red in the appearance stream), ... I want to set the dictionary contents to the appearance stream. This problem occurs in some PDFs that are created in Foxit and then opened in Adobe.

不幸的是,PDF 允许通过多种方式创建类似的效果。绘制边框,例如,

  • 你可以划出一条四线的路径,
  • 或者你可以画一个矩形,
  • 或者您可以填充一个矩形并用白色填充另一个稍小的内部矩形,
  • 或者您可以用矩形蒙版填充所有内容,
  • 或者您可以绘制具有所需形式的位图,
  • 或者你可以...
  • ...

因此,针对您的问题的真正通用解决方案介于极其复杂和不可能之间。

此外,仅使用注释词典中有限的抽象设置可能无法表示某些外观。例如。外观流中的边框可能在中间创建为实心但使用透明度向左和向右淡出,或者它可能使用颜色渐变运算符绘制,导致颜色渐变,或者它的形状可能不是完全矩形而是不规则的,或者,或者,...


如果您不是在寻找通用解决方案,而只是寻找适用于某些软件产品(如 Foxit)在某些版本中创建的注释的解决方案,并且该软件创建的外观是否可以使用抽象来表示注释字典值,任务变得可行。

在这种情况下,您应该首先分析由这些软件产品创建的样本外观流。很可能会出现某种模式。

一旦找到该模式,您就可以开始实施匹配的 iTextSharp 5.5.x IExtRenderListener 或 iTextSharp 7.0.x IEventListener.