Как получить номер страницы или ссылку на страницу для места назначения Outline в PDF на iOS? - PullRequest
6 голосов
/ 10 января 2011

Я прочитал спецификацию Adobe PDF, а также документацию Apple Quartz 2D для рендеринга и анализа PDF. Я также скачал Voyeur и проверил местный PDF с ним, чтобы увидеть его внутренние данные. На данный момент я могу получить каталог документов, а затем получить оттуда словарь контуров. Я вижу, что вложенные в словари контуров словаря, что есть узлы с именем "/ Dest" со значениями, такими как:

G1.1025588 и т.д.

Мне интересно, есть ли способ использовать эти значения, чтобы получить ссылку на страницу для рендеринга, используя некоторые методы, которые я видел в таких проектах github, как Reader, вместе с документированными примерами apple.

Обработка PDF определенно является проблемой, поэтому любая помощь будет признательна.

Ответы [ 2 ]

3 голосов
/ 13 января 2011

Запись /Dest в словаре элементов структуры может представлять собой имя , строку или массив .

  • Самый простой случай, если это массив ;затем первый элемент - это объект страницы, на который указывает элемент схемы (словарь).Чтобы получить номер страницы, вам нужно перебрать все страницы документа и посмотреть, какая из них равна (==) имеющемуся у вас словарю (CGPDFPageRef s на самом деле CGPDFDictionaryRef s).Вы также можете пройти по дереву страниц, которое немного сложнее, но может быть быстрее (не так много, как вы ожидаете, я бы здесь не оптимизировал преждевременно).Другие элементы в массиве - это позиция на странице и т. Д., Для получения дополнительной информации найдите «Явные места назначения» в спецификации PDF.

  • Если запись является name или строка , это именованный пункт назначения.Необходимо сопоставить имя с пунктом назначения из записи /Dests каталога документов, которая представляет собой словарь, содержащий дерево имен.Дерево имен - это, по сути, древовидная карта, которая обеспечивает быстрый доступ к именованным значениям без необходимости считывать все данные сразу (как в обычном словаре).К сожалению, в Quartz нет прямой поддержки деревьев имен, поэтому вам придется немного проделать рекурсивный анализ этой структуры (см. «Деревья имен» в PDF spec ).

Обратите внимание, что элемент структуры не обязательно имеет запись /Dest, он также может указать свое назначение с помощью записи /A (действие), которая немного сложнее.Однако в большинстве случаев это будет действие «GoTo», которое по сути является оберткой для пункта назначения.

Отображение имен в пункты назначения также может быть сохранено в виде простого словаря.В этом случае он находится в записи /Dests словаря / Names в каталоге документа.Хотя я редко видел это, и это устарело после PDF 1.2 (текущий 1.7).

Для этого вам определенно понадобится спецификация PDF: http://www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf

0 голосов
/ 15 декабря 2011

Благодаря Omz, здесь есть фрагмент кода для получения номера страницы для конечного пункта в файле PDF:

// Get Page Number from an array
- (int) getPageNumberFromArray:(CGPDFArrayRef)array ofPdfDoc:(CGPDFDocumentRef)pdfDoc withNumberOfPages:(int)numberOfPages
{
    int pageNumber = -1;

    // Page number reference is the first element of array (el 0)
    CGPDFDictionaryRef pageDic;
    CGPDFArrayGetDictionary(array, 0, &pageDic);

    // page searching
    for (int p=1; p<=numberOfPages; p++)
    {
        CGPDFPageRef page = CGPDFDocumentGetPage(pdfDoc, p);
        if (CGPDFPageGetDictionary(page) == pageDic)
        {
            pageNumber = p;
            break;
        }
    }

    return pageNumber;
}

// Get page number from an outline. Only support "Dest" and "A" entries
- (int) getPageNumber:(CGPDFDictionaryRef)node ofPdfDoc:(CGPDFDocumentRef)pdfDoc withNumberOfPages:(int)numberOfPages
{
    int pageNumber = -1;

    CGPDFArrayRef destArray;
    CGPDFDictionaryRef dicoActions;
    if(CGPDFDictionaryGetArray(node, "Dest", &destArray))
    {
        pageNumber = [self getPageNumberFromArray:destArray ofPdfDoc:pdfDoc withNumberOfPages:numberOfPages];
    }
    else if(CGPDFDictionaryGetDictionary(node, "A", &dicoActions))
    {
        const char * typeOfActionConstChar;
        CGPDFDictionaryGetName(dicoActions, "S", &typeOfActionConstChar);

        NSString * typeOfAction = [NSString stringWithUTF8String:typeOfActionConstChar];
        if([typeOfAction isEqualToString:@"GoTo"]) // only support "GoTo" entry. See PDF spec p653
        {
            CGPDFArrayRef dArray;
            if(CGPDFDictionaryGetArray(dicoActions, "D", &dArray)) 
            {
                pageNumber = [self getPageNumberFromArray:dArray ofPdfDoc:pdfDoc withNumberOfPages:numberOfPages];
            }
        }
    }

    return pageNumber;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...