2012-04-10 18 views
8

Sé que puedo 'linealizar' un archivo PDF, por ejemplo, usando Acrobat SDK o usando herramientas comerciales. Esto también se llama 'optimizado para web' y reorganiza el PDF para que la página 1 pueda cargarse lo más rápido posible. Los PDF servidos de esta manera se muestran más rápidamente, porque el visor de PDF no tiene que esperar a que se descargue todo el PDF.¿Cómo puedo determinar la extensión (en bytes) de la página 1 en un archivo PDF linealizado?

Actualización: basado en respuesta a continuación, ahora se dan cuenta de que un PDF linealizado no es sólo reorganizado, pero también contiene metadatos acerca de su propia estructura, en la forma del "diccionario linealización".

Tengo una aplicación donde quiero recuperar varios PDF (los resultados de una consulta) en anticipación de que el usuario querrá ver uno de ellos. Sería increíble si mi cliente pudiera descargar la página 1, y solo la página 1, para cada uno de los resultados de búsqueda. Cuando el usuario selecciona uno de ellos, la página 1 se puede mostrar al instante y el resto se puede descargar en segundo plano.

Estoy buscando una solución general que se pueda usar en el lado del servidor (Windows o Linux) para preprocesar mis archivos PDF, de modo que pueda almacenar y servir la página 1 y el resto por separado. Realmente, todo lo que necesito saber es dónde está el PDF en el último byte necesario para mostrar correctamente la página 1. Si puedo tener este número, todo lo demás sigue.

He navegado por el ISO specification for PDF pero el formato de archivo parece demasiado complejo para que simplemente analice dónde termina la página 1. Por otro lado, las herramientas que linealizan los archivos PDF casi seguramente deben saber dónde termina la página 1.

No me interesan las complicaciones de entregar archivos PDF en piezas a los clientes; Esta parte ya está resuelta ya que el cliente es una aplicación, no un navegador, y tengo control total.

Tampoco creo que me ayude a dividir el PDF usando herramientas como AP Split en un PDF de "página 1" y un PDF completo. Si lo hago, no podré engañar al cliente espectador para que piense que es un único archivo PDF, y habrá un parpadeo notable cuando reemplace el PDF "página 1" con el PDF completo.

Cualquier ayuda o consejos apreciados.

Solución (basado en la respuesta de Bobrovsky abajo):

Un adecuadamente linealizado PDF comienza con una línea de cabecera (que se define en la sección 7.5.2 de la especificación PDF) como "% PDF-1.7", seguido de una línea de comentario de al menos cuatro caracteres binarios (definidos como valores de bytes de 128 o más). Por ejemplo:

%PDF-1.7 
    %¤¤¤¤ 

Esta cabecera es seguida inmediatamente por el diccionario de linealización (definido en el Apéndice F en la especificación PDF). Un ejemplo:

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 

En este ejemplo, el final de la primera página es compensado en el byte 5437. Esta estructura de datos es lo suficientemente simple para analizar el uso de casi cualquier idioma. La cosa "43 0 obj" da una ID para este diccionario (43) y un número de generación (siempre cero para archivos linealizados). El diccionario está rodeado por < < y >>, entre los cuales hay pares de valores clave (las teclas tienen barras como "/ E").

Y aquí es un método C# que se encuentra el número correspondiente utilizando una expresión regular:

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+(?<offset>\d+).+>>"); 
    if (!match.Success) throw new InvalidDataException("PDF does not have a proper linearization dictionary"); 
    return int.Parse(match.Groups["offset"].Value); 
} 

Nota salvedad de Bobrovsky que un archivo puede contener el diccionario linealización, sin embargo, no puede ser linealizado adecuadamente (tal vez debido a una edición incrementales ?). En mi caso, esto no es un problema, ya que voy a linealizar todos los PDF.

+1

Otra advertencia: he visto archivos PDF con bytes basura entre el encabezado y el inicio del diccionario de linealización. – Bobrovsky

Respuesta

3

El diccionario de linealización debería ayudarlo con esto.

El diccionario requerido para contener E parámetro que es

el desplazamiento del extremo de la primera página (el extremo de la parte 6 en el Ejemplo F.1), en relación con el principio del archivo.

Tenga en cuenta que no todos los archivos con un diccionario linealización es en realidad linealizado (generadores rotos, los cambios después de la linealización, etc.) Por lo tanto, es posible que no pueda utilizar el enfoque descrito si sus archivos no se verifican ser adecuadamente linealizado .

Por favor, eche un vistazo a F.2.2 Diccionario de parámetros de linealización (Parte 2) en referencia de PDF para obtener más información sobre el diccionario de linealización.

Cuestiones relacionadas