Как определить размер (в байтах) страницы 1 в линеаризованном файле PDF?

Я знаю, что могу «линеаризовать» PDF-файл, например, с помощью Acrobat SDK или коммерческих инструментов. Это также называется «оптимизированным для Интернета» и перестраивает PDF-файл так, чтобы страница 1 загружалась как можно быстрее. PDF-файлы, обслуживаемые таким образом, отображаются быстрее, поскольку средству просмотра PDF-файлов не нужно ждать загрузки всего PDF-файла.

Обновление: основываясь на приведенном ниже ответе, теперь я понимаю, что линеаризованный PDF-файл не просто переупорядочивается, но также содержит метаданные о своей собственной структуре в виде «словаря линеаризации».

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

Я ищу общее решение, которое можно использовать на стороне сервера (Windows или Linux) для предварительной обработки моих PDF-файлов, чтобы я мог хранить и обслуживать страницу 1 и остальные по отдельности. На самом деле все, что мне нужно знать, это где в PDF-файле находится последний байт, необходимый для правильного отображения страницы 1. Если я смогу получить этот номер, все остальное следует.

Я просмотрел спецификацию ISO для PDF, но формат файла кажется мне слишком сложным, чтобы просто проанализировать, где заканчивается страница 1. С другой стороны, инструменты, которые линеаризуют PDF-файлы, почти наверняка должны знать, где заканчивается страница 1.

Меня не интересуют сложности доставки PDF-файлов клиентам по частям; эта часть уже решена, поскольку клиент — это приложение, а не браузер, и у меня есть полный контроль.

Я также не думаю, что это поможет мне разделить PDF-файл с помощью таких инструментов, как AP Split, на PDF-файл «страница 1» и полный PDF-файл. Если я это сделаю, то я не смогу обмануть средство просмотра клиента, заставив его думать, что это один файл PDF, и будет заметно мерцание, когда я заменю PDF-файл «страница 1» полным PDF-файлом.

Любая помощь или подсказки приветствуются.

Решение(на основе ответа Бобровского ниже):

Правильно линеаризованный PDF-файл начинается со строки заголовка (определенной в разделе 7.5.2 спецификации PDF), такой как «%PDF-1.7», за которой следует строка комментария, состоящая не менее чем из четырех двоичных символов (определяемых как байтовые значения 128 или выше). Например:

    %PDF-1.7
    %¤¤¤¤

За этим заголовком сразу следует словарь линеаризации (определенный в Приложении F спецификации PDF). Пример:

    43 0 obj
    << /Linearized 1.0 % Version
     /L 54567   % File length
     /H [475 598] % Primary hint stream offset and length (part 5)
     /O 45      % Object number of first page’s page object (part 6)
     /E 5437    % Offset of end of first page
     /N 11      % Number of pages in document
     /T 52786 % Offset of first entry in main cross-reference table (part 11)
    >>
    endobj

В этом примере конец первой страницы находится по смещению 5437 в байтах. Эта структура данных достаточно проста для анализа практически на любом языке. Элемент «43 0 obj» дает идентификатор для этого словаря (43) и номер поколения (всегда ноль для линеаризованных файлов). Сам словарь окружен >, между которыми находятся пары ключ-значение (ключи имеют косую черту, например "/E").

А вот метод C#, который находит релевантное число с помощью регулярного выражения:

public int GetPageOneLength(byte[] data)
{
  // According to ISO PDF spec: "The linearization parameter dictionary shall be entirely contained within the first 1024 bytes of the PDF file" (p. 679)
  string preamble = new string(ASCIIEncoding.ASCII.GetChars(data, 0, 1024));    // Note that the binary section on line 2 of the header will be entirely converted to question martks ('?')
  var match = Regex.Match(preamble, @"<<\w*/Linearized.+/E\s+(?\d+).+>>");
  if (!match.Success) throw new InvalidDataException("PDF does not have a proper linearization dictionary");
  return int.Parse(match.Groups["offset"].Value);
}

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

8
задан Sten L 17 April 2012 в 09:40
поделиться