PDF Text Extraction в местах гиперссылок - PullRequest
3 голосов
/ 22 октября 2010

Кто-нибудь знает о (БЕСПЛАТНО) каком-либо SDK, который может начать извлечение текста в том месте документа PDF, куда вас ведет гиперссылка (в том же документе PDF)?Ссылки в итоге приводят нас к конкретным пунктам на определенных страницах.

В частности, нам нужна программа, которая может анализировать PDF-документ, содержащий вопросы и ответы на тест (а также соответствующие примечания для каждого вопроса / ответа)) и экспортировать только нужные нам части в текстовый файл.

В основном документ PDF содержит тестовые вопросы в начале документа, и внутри каждого вопроса есть гиперссылка на его ответ и соответствующие примечания в другой части документа PDF.

PS - Использование одногоследующих языков: C ++, Java, VB.net, C # .net, javascript PPS - только свободное программное обеспечение

Ответы [ 3 ]

1 голос
/ 27 октября 2010

Это сложнее, чем кажется - вам, возможно, придется переосмыслить свой вопрос.Внутридокументные гиперссылки обычно создаются посредством аннотации ссылок с целевым назначением для действия «Перейти к просмотру».Эта точка зрения не обязательно включает границы или даже точку.Иногда это просто страница (при текущем увеличении) или страница (по ширине подгонки) или страница (вверху, определенный масштаб).И это еще сложнее, чем то, потому что назначение ссылки может быть деревом действий, которые нужно выполнить, чтобы каждое действие было одним из 18 возможных типов действий, включая javascript, который можно использовать, чтобы заставить зрителя перейти к определенному месту назначения.

Думаю, у вас также возникнут проблемы с «в том месте, куда вас ведет ссылка».

Многие из этих задач можно выполнить в C # с помощью Atalasoft dotAnnotate и добавления извлечения PDF-текста.(отказ от ответственности, я работаю в Atalasoft, написал импортер аннотаций PDF-> и работал для Adobe в 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 и начните обходить дерево действий, чтобы найти действие с ключом / типом, установленным в / GoTo (IIRC), а затем перейдите оттуда.

Пункт назначения может быть прямым пунктом назначения или именованным пунктом назначения.Если это именованный пункт назначения, вам придется вернуться в каталог документов, вытащить дерево имен и найти его по названию в названном месте назначения, а когда вы его найдете, вытащить информацию там.

Так что, да, вы можете использовать iText или другой подобный парсер PDF, но вам нужно будет выполнить все эти шаги, если только один из создателей библиотеки не проявил к вам такой любезности.

1 голос
/ 02 ноября 2010

Я не знаю ни одного платного или бесплатного программного обеспечения, которое могло бы делать из коробки то, что вам нужно. Вам, вероятно, придется написать некоторый код независимо от того, какую библиотеку вы будете использовать. В конце концов, текст в PDF может быть в любом порядке, поэтому, по крайней мере, текстовые координаты должны быть рассчитаны для правильной фильтрации нежелательного текста. Кроме того, ссылки на аннотации должны быть найдены в формате PDF, а также должна быть получена информация об их пунктах назначения.

Библиотека Docotic.Pdf (отказ от ответственности: я работаю в Bit Miracle) может помочь вам как с аннотациями, так и с текстовыми координатами. Существует пример « Извлечь текст из цели ссылки », который иллюстрирует, как сделать что-то похожее на вашу задачу. Я публикую ссылку на образец в надежде, что он может быть полезен для вас (если вы решите обратиться к несвободному программному обеспечению) или другим.

0 голосов
/ 22 октября 2010

iText (Java & C #) может это сделать, хотя и не «из коробки». Вам нужно будет выполнить некоторые низкоуровневые манипуляции с объектами PDF (и немного математики), чтобы определить, с чего начать поиск, например.

Хорошей новостью является то, что существует «стратегия» извлечения текста, которая будет извлекать текст только из заданного ограничивающего прямоугольника. Код может выглядеть примерно так:

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

Получение пункта назначения по ссылке - это не просто полезный пример. Вам нужно будет ознакомиться со спецификацией PDF (у Adobe есть бесплатная копия ... она упоминается в нескольких других вопросах с тегами PDF, но у меня нет ссылки на этом компьютере).

...