3

有人知道某种(免费)SDK 可以在 PDF 文档中超链接带您到的位置(在同一个 PDF 文档中)开始文本提取吗?这些链接最终将我们带到特定页面上的特定点。

更具体地说,我们需要一个可以解析包含测试问题和答案(以及每个问题/答案的相关注释)的 pdf 文档的程序,并且只将我们需要的相关部分导出到文本文件中。

基本上,PDF 文档在文档开头有测试问题,每个问题中都有一个超链接,指向 PDF 文档另一部分的答案和相关注释。

PS - 使用以下语言之一:C++、Java、VB.net、C#.net、javascript PPS - 仅限免费软件

4

3 回答 3

1

我不知道有任何付费或免费软件可以开箱即用地满足您的需求。无论您将使用什么库,您可能都必须编写一些代码。毕竟,PDF 中的文本可以按任何顺序排列,因此至少应该计算文本坐标以正确过滤掉不需要的文本。此外,应在 PDF 中找到链接注释,并检索有关其目的地的信息。

Docotic.Pdf 库(免责声明:我为 Bit Miracle 工作)可以帮助您处理注释和文本坐标。有一个“从链接目标中提取文本”示例说明如何执行与您的任务类似的操作。我发布示例的链接,希望它对您(如果您决定转向非自由软件)或其他人有用。

于 2010-11-02T15:29:51.890 回答
1

这比听起来更难——你可能需要重新考虑你的问题。文档内超链接通常通过链接注释来完成,其中目标设置为“转到视图”操作。这种观点不一定包括界限甚至一点。有时它只是一个页面(当前缩放)或一个页面(适合宽度)或一个页面(在顶部,特定缩放)。它甚至比这更复杂,因为链接目标可能是按顺序执行的操作树,每个操作都是 18 种不同可能的操作类型之一,包括可用于驱使查看者前往特定目的地的 javascript。

我认为你也会在“链接到你的地方”遇到麻烦。

您可以使用 Atalasoft dotAnnotate 和 PDF 文本提取插件在 C# 中完成很多此任务(免责声明,我为 Atalasoft 工作,编写了 PDF->annotations 导入器,并曾在 Acrobat v 1、2 和3)。不,对不起,它不是免费软件。

这就是我的做法(免责声明 - 这就是我的想法):

class PageAnnots : KeyValuePair<int, List<PdfLinkData>> { }

public PageAnnots GetPageLinkDestinations(Stream stm)
{
    PdfAnnotationDataImporter importer = new PdfAnnotationDataImporter(stm);
    List<PageAnnots> pageAnnots = new List<PageAnnots>();

    try {
        importer.Load();
        // this gets all annotations on all pages.  On long docs, this will be time consuming
        AnnotationDataCollection allAnnots = importer.Import();
        int pageNo = 0;
        // allAnnots is a collection of LayerData, each LayerData object being a collection
        // of annots for a page.  The collection is empty if there are no annots
        foreach (AnnotationData pageOfAnnots in allAnnots) {
            List<PdfLinkData> linkAnnots = new List<PdfLinkData>();
            LayerData pageLayer = pageOfAnnots as LayerData;
            if (pageLayer != null) {
                // filter out each annot that is a link
                foreach (AnnotationData annot in pageLayer.Items) {
                    PdfLinkData link = annot as PdfLinkData;
                    if (link != null)
                        linkAnnots.Add(link);
                }
            }
            if (linkAnnots.Count > 0) {
                pageAnnots.Add(new PageAnnots(pageNo, linkAnnots));
            }
            pageNo++;
        }
    }
    catch (Exception err) {
        // keep it?  drop it?
    }

    return pageAnnots;
}

此时,我们已将其简化为键值对的集合,每个键是页码,每个值是表示该页面上链接的 PdfLinkData 对象的非空列表。

从那里,您可以遍历此集合并尝试像这样计算目标:

private int PageFromDestination(PdfDestination dest)
{
    PdfIndexedPageReference pageRef = dest.Page as PdfIndexedPageReference;
    return pageRef == null ? -1 : pageRef.PageIndex;
}

public void FigureDestination(PdfLinkData link)
{
    PdfActionList actions = link.ClickAction;
    foreach (PdfAction action in actions) {
        PdfGoToViewAction gotoView = action as PdfGoToViewAction;
        if (action == null)
            continue;
        // this only pulls the page from the destination.  The dest
        // may also contain information about the view.  I'm assuming you
        // only want the page number
        int page = PageFromDestination(gotoView.Destination);
        if (page >= 0) {
            // here's where you step in - the click action could be
            // a long chain of things including several GoToView actions.
            // it's up to you to decide what you want to do.  Handle only
            // action lists of length 1?  Stop at first GoToView?
            // aggregate them all?
        }
    }
}

当您查看此代码时,您会想知道为什么在索引页面引用、操作类型和操作列表方面存在这种抽象级别?答案是 GoToView 操作也可以引用另一个文档——跨文档链接在 PDF 中有效。虽然 dotAnnotate 现在不支持它们,但它有望在未来支持它们。类似地,该操作可以指示转到嵌入 PDF 文档中的视图(是的,您可以在 PDF 中嵌入 PDF)。

您需要注意 dotAnnotate 为您提供了一组有限的相当高级的对象,并且不需要您了解和理解 PDF 规范(太多)。过去,我们曾尝试将非常精细的 API 发布到 TIFF 之类的东西中,但发现我们的客户并不觉得它们可口。因此,我们试图猜测我们的客户可能想要和需要什么,并创建更易于消化的 API。

iText 和 iTextSharp 为您提供了对 API 的非常精细的控制,但您需要了解 PDF 规范才能获得所需的内容。

例如,要进行注释提取,您将必须打开文档,获取页面目录,遍历页面树,找到所有具有 Annots 键的页面字典,遍历 Annots 数组,搜索其中的每个字典以查找键/Type 的值为 /Annot 和键 /SubType 的值为 /Link,然后提取键 /Dest 的值(如果存在),如果它不为空,则使用该键,否则查看键 /A 并开始走动作树找到一个键 /Type 设置为 /GoTo (IIRC) 的动作,然后从那里开始。

目的地可以是直接目的地,也可以是命名目的地。如果它是一个命名的目的地,您将不得不返回文档目录并拉出名称树并在命名目的地中搜索名称,当您找到它时,将那里的信息拉出。

所以,是的,您可以使用 iText 或其他类似的 PDF 解析器,但您需要执行所有这些步骤,除非其中一位库创建者愿意为您执行此操作。

于 2010-10-26T20:25:48.167 回答
0

iText (Java & C#) 可以做到,虽然不是“开箱即用”。您必须进行一些低级 PDF 对象操作(和一些数学运算)来确定从哪里开始查找示例。

好消息是有一个文本提取“策略”,它只会从给定的边界框中提取文本。代码可能如下所示:

http://www.itextpdf.com/examples/iia.php?id=279

从链接获取目的地并不是一个方便的例子。您必须查看 PDF 规范(adobe 提供免费副本......在其他几个带有 PDF 标记的问题中提到,但我在这台机器上没有方便的链接)。

于 2010-10-22T05:39:01.540 回答