任何人都知道某种(免费)SDK可以在PDF文档中开始文本提取,超链接将您带到(在同一PDF文档中)?链接最终将我们带到特定页面上的特定点。
更具体地说,我们需要一个能够解析pdf文档的程序,该文档包含测试的问题和答案(以及每个问题/答案的相关注释),并且只将我们需要的相关部分导出到文本文件中。
基本上,PDF文档在文档开头有测试问题,每个问题内都有一个超链接,指向PDF文档另一部分的答案和相关注释。
P.S。 - 使用以下语言之一:C ++,Java,VB.net,C#.net,javascript P.P.S. - 仅限免费软件
答案 0 :(得分:1)
这比听起来更难 - 你可能需要重新考虑你的问题。内部文档超链接通常通过链接注释完成,目标设置为“转到视图”操作。该观点不一定包括界限甚至是一点。有时它只是一个页面(当前缩放)或页面(适合宽度)或页面(在顶部,特定缩放)。而且它甚至比这复杂得多,因为链接目的地可以是按顺序采取的动作树,每个动作是18种不同的可能动作类型之一,包括可以用来驱动观众去特定目的地的javascript。
我认为你也会遇到“在链接带你的地方。”
您可以使用Atalasoft dotAnnotate在C#中执行大量此任务,并添加PDF文本提取(免责声明,我为Atalasoft工作,编写PDF-> annotations导入程序,并且曾经在Acrobat v 1上为Adobe工作,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数组,搜索其中的每个词典对于具有值/ Annot的键/类型,对于具有值/ Link的键/子类型,然后拉出键/ Dest的值(如果存在)并且如果它是非空的,则以其他方式查看键/ A和开始走动作树,找到一个关键/类型设置为/ GoTo(IIRC)的动作,然后从那里开始。
目的地可以是直接目的地,也可以是指定目的地。如果它是一个命名目的地,你将不得不返回文档目录并提取名称树并在命名目的地中搜索它的名称,当你找到它时,在那里提取信息。
所以是的,您可以使用iText或其他类似的PDF解析器,但除非其中一位图书馆创建者对您这样做,否则您需要执行所有这些步骤。
答案 1 :(得分:1)
我不知道任何付费或免费软件可以满足您的需求。无论您将使用哪个库,您都可能需要编写一些代码。毕竟,PDF中的文本可以按任何顺序排列,因此至少应计算文本坐标以正确过滤掉不需要的文本。此外,应在PDF中找到链接注释,并应检索有关其目的地的信息。
Docotic.Pdf Library(免责声明:我为Bit Miracle工作)可以帮助您完成注释和文本坐标。有一个“Extract text from link target”示例说明了如何执行与您的任务类似的操作。我发布了样本的链接,希望它对您有用(如果您决定使用非自由软件)或其他。
答案 2 :(得分:0)
iText(Java&amp; C#)可以做到,但不是“开箱即用”。您必须进行一些低级PDF对象操作(以及一些数学运算)以确定从哪里开始查找示例。
好消息是,文本提取“策略”只能从给定的边界框中提取文本。代码可能如下所示:
http://www.itextpdf.com/examples/iia.php?id=279
通过链接获取目的地并不是一个方便的例子。你将不得不看看PDF规范(adobe有一个免费的副本......在其他几个PDF标记的问题中提到它,但我没有在这台机器上方便的链接。)