CombinePDF es un modelo ingenioso, escrito en Pure Ruby, para analizar los archivos PDF y combinarlos (fusionar) con otros archivos PDF, marcarlos o sellarlos (todos utilizando el formato de archivo PDF y el código de rubí puro).
Decidí dejar de mantener esta gema y esperar que alguien pueda hacerse cargo de las revisiones de relaciones públicas y el mantenimiento de esta gema (o simplemente abrir una bifurcación exitosa).
Escribí esta joya porque necesitaba resolver un problema con los documentos PDF existentes de Bates.
Sin embargo, desde 2014 he estado manteniendo la gema de forma gratuita y sin ninguna razón, excepto que disfruté compartirla con la comunidad.
Me encanta esta joya, pero no puedo seguir manteniéndola, ya que tengo mis propios proyectos para concentrarme y necesito tanto el tiempo como (lo que es más importante) el espacio mental.
Instalar con gemas Ruby:
gem install combine_pdf
Resumen rápido:
Al leer formularios PDF, se pueden perder algunos datos de formulario. Intenté arreglar esto lo mejor que pueda, pero no estoy seguro de que todo funcione todavía.
Al combinar formularios PDF, los datos de formulario pueden estar unificados. No pude solucionar esto porque así es como funcionan los formularios PDF (llenar un campo llena los datos en cualquier campo con el mismo nombre), pero, francamente, me gustó el problema ... es casi una característica.
Al unificar los mismos datos de TOC más de una vez, una de las referencias se unificará con la otra (lo que significa que si las páginas se ven iguales, ambas referencias se unirán a la misma página en lugar de vincular a dos páginas diferentes). Puede solucionar esto agregando contenido a las páginas antes de fusionar los archivos PDF (es decir, agregue cuadros de texto vacíos a todas las páginas).
Algunos enlaces y datos (enlaces de URL y PDF "destinados nombrados") se almacenan en la raíz de un PDF y no están vinculados desde la página. Mantener esta información requiere fusionar los objetos PDF en lugar de sus páginas.
Algunos enlaces se perderán al arrancar páginas de los archivos PDF y fusionarlos con otro PDF.
Algunos archivos PDF cifrados (generalmente los que no puede ver sin una contraseña) fallarán en silencio en lugar de ruidosamente. Si prefiere elegir la ruta ruidosa, puede especificar la opción raise_on_encrypted
usando CombinePDF.load(pdf_file, raise_on_encrypted: true)
que elevará un CombinePDF::EncryptionError
.
A veces, el CombinePDF aumentará una excepción incluso si el PDF podría analizarse (es decir, cuando existe el contenido opcional PDF) ... Me resulta mejor errar por precaución, aunque para el contenido opcional PDFS se puede evitar una excepción usando CombinePDF.load(pdf_file, allow_optional_content: true)
.
CombinePDF GEM ejecuta código recursivo para analizar y formatear los archivos PDF. Por lo tanto, los archivos PDF que tienen objetos muy anidados, así como aquellos que se combinan de una manera que resulta en la anidación cíclica, podrían explotar la pila, lo que resulta en una excepción o falla del programa.
CombinePDF se escribe de forma nativa en Ruby y debería (presumiblemente) trabajar en todas las plataformas Ruby que siguen la compatibilidad de Ruby 2.0.
Sin embargo, los archivos PDF son criaturas bastante complejas y no se proporciona garantía.
Por ejemplo, se sabe que los formularios PDF tienen problemas y los datos de formulario pueden perderse al intentar combinar PDF con datos de formulario rellenos (también, los formularios son objetos globales, no específicos de la página, por lo que uno debe combinar el total de los datos para cualquier dato para cualquier dato. tener alguna posibilidad de ser preservado).
Lo mismo se aplica a los enlaces PDF y la tabla de contenido, que tienen atributos globales y podrían corrompirse o perderse al combinar datos PDF.
Si esta biblioteca causa pérdida de datos o quema su casa, no tengo la culpa, como lo señaló la licencia del MIT. Dicho esto, estoy usando la biblioteca feliz después de probar con diferentes soluciones.
Para combinar archivos PDF (o datos):
pdf = CombinePDF . new
pdf << CombinePDF . load ( "file1.pdf" ) # one way to combine, very fast.
pdf << CombinePDF . load ( "file2.pdf" )
pdf . save "combined.pdf"
O incluso un delineador:
( CombinePDF . load ( "file1.pdf" ) << CombinePDF . load ( "file2.pdf" ) << CombinePDF . load ( "file3.pdf" ) ) . save ( "combined.pdf" )
También puede agregar páginas extrañas o incluso impares:
pdf = CombinePDF . new
i = 0
CombinePDF . load ( "file.pdf" ) . pages . each do | page |
i += 1
pdf << page if i . even?
end
pdf . save "even_pages.pdf"
Observe que agregar todas las páginas una por una es más lenta y luego agregar todo el archivo.
Para agregar contenido a las páginas PDF existentes, primero importe el nuevo contenido desde un archivo PDF existente. Después de eso, agregue el contenido a cada una de las páginas de su PDF existente.
En este ejemplo, agregaremos un logotipo de la empresa a cada página:
company_logo = CombinePDF . load ( "company_logo.pdf" ) . pages [ 0 ]
pdf = CombinePDF . load "content_file.pdf"
pdf . pages . each { | page | page << company_logo } # notice the << operator is on a page and not a PDF object.
pdf . save "content_with_logo.pdf"
Observe que el operador << está en una página y no en un objeto PDF. El operador << actúa de manera diferente en los objetos PDF y en las páginas.
El operador << del operador se debe asegurar la inyección al cambiar las referencias para evitar los conflices. Para superponer páginas utilizando datos comprimidos que podrían no ser editables (debido a un soporte de filtro limitado), puede usar:
pdf . pages ( nil , false ) . each { | page | page << stamp_page }
Agregar números de página a un objeto o archivo PDF es lo más simple posible:
pdf = CombinePDF . load "file_to_number.pdf"
pdf . number_pages
pdf . save "file_with_numbering.pdf"
La numeración se puede hacer con muchas opciones diferentes, con una formación diferente, con o sin un objeto de caja, e incluso con valores de opacidad, consulte la documentación.
Por ejemplo, si prefiere colocar el número de página en la parte inferior derecha de todas las páginas PDF, hacer:
pdf . number_pages ( location : [ :bottom_right ] )
Como otro ejemplo, se eliminan los guiones alrededor del número y se coloca una caja a su alrededor. La numeración es semitransparente y las primeras 3 páginas están numeradas usando letras (a, b, c) en lugar de números:
# number first 3 pages as "a", "b", "c"
pdf . number_pages ( number_format : " %s " ,
location : [ :top , :bottom , :top_left , :top_right , :bottom_left , :bottom_right ] ,
start_at : "a" ,
page_range : ( 0 .. 2 ) ,
box_color : [ 0.8 , 0.8 , 0.8 ] ,
border_color : [ 0.4 , 0.4 , 0.4 ] ,
border_width : 1 ,
box_radius : 6 ,
opacity : 0.75 )
# number the rest of the pages as 4, 5, ... etc'
pdf . number_pages ( number_format : " %s " ,
location : [ :top , :bottom , :top_left , :top_right , :bottom_left , :bottom_right ] ,
start_at : 4 ,
page_range : ( 3 ..- 1 ) ,
box_color : [ 0.8 , 0.8 , 0.8 ] ,
border_color : [ 0.4 , 0.4 , 0.4 ] ,
border_width : 1 ,
box_radius : 6 ,
opacity : 0.75 )
pdf.number_pages(number_format: " %s ", location: :bottom_right, font_size: 44)
La carga de datos PDF se puede realizar desde el sistema de archivos o directamente desde la memoria.
Cargar datos de un archivo es fácil:
pdf = CombinePDF . load ( "file.pdf" )
También puede analizar archivos PDF desde la memoria. La carga de la memoria es especialmente efectiva para importar datos PDF recibidos a través de Internet o desde una biblioteca de autor diferente, como el langostino:
pdf_data = prawn_pdf_document . render # Import PDF data from Prawn
pdf = CombinePDF . parse ( pdf_data )
El uso de parse
también es efectivo al cargar datos desde una ubicación remota, eludiendo la necesidad de archivos temporales innecesarios. Por ejemplo:
require 'combine_pdf'
require 'net/http'
url = "https://example.com/my.pdf"
pdf = CombinePDF . parse Net :: HTTP . get_response ( URI . parse ( url ) ) . body
Del mismo modo, a la carga y el análisis, la representación también se puede realizar en la memoria o en un archivo.
Puede generar una cadena de datos PDF usando .to_pdf
. Por ejemplo, para que un usuario descargue el PDF desde una aplicación Rails o una aplicación Plezi:
# in a controller action
send_data combined_file . to_pdf , filename : "combined.pdf" , type : "application/pdf"
En Sinatra:
# in your path's block
status 200
body combined_file . to_pdf
headers 'content-type' => "application/pdf"
Si prefiere guardar los datos PDF en un archivo, siempre puede usar el método save
como lo hicimos en nuestros ejemplos anteriores.
Algunos archivos PDF contienen secciones de contenido opcionales que no siempre se pueden fusionar de manera confiable. Por defecto, se plantea una excepción si se detecta uno de estos archivos. Opcionalmente, puede pasar un parámetro allow_optional_content
al PDFParser.new
, CombinePDF.load
y CombinePDF.parse
.
new_pdf = CombinePDF . new
new_pdf << CombinePDF . load ( pdf_file , allow_optional_content : true )
attachments . each { | att | new_pdf << CombinePDF . load ( att , allow_optional_content : true ) }
Puede ver una demostración para una "aplicación web de Bates Stumping" y leer su código. Buena suerte :)
Algunos archivos PDF están encriptados y otros están comprimidos (el uso de filtros) ...
Hay muy poco soporte para archivos cifrados y soporte muy básico y limitado para archivos comprimidos.
Necesito ayuda con eso.
Si desea ayudar con el código, tenga en cuenta:
Soy un hobbbiest de corazón. Falta la documentación y los comentarios en el código son malas guías.
El código en sí debería ser muy sencillo, pero no dude en preguntar lo que quiera.
Stefan Leitner (@SLE1Tner) escribió el código de fusión de esquema que admite PDF que contienen un TOC.
Caige Nichols escribió una increíble gema RC4 que usé en mi código.
Quería instalar la gema, pero tuve problemas con Internet y terminé copiando el código en sí en el archivo Combine_PDF_Decrypt de clase.
El crédito a su maravilloso se da aquí. Respeta su licencia y derechos de autor ... y los míos.
MIT
Puede mirar la página de problemas de GitHub y ver las etiquetas "Ayuda Wanted".
Si está pensando en donaciones o enviándome dinero, no es necesario. Este proyecto puede sostenerse sin su dinero.
Lo que este proyecto necesita es el tiempo dado por los desarrolladores cariñosos que lo mantienen actualizado y solucionan cualquier error de documentación o problema que noten ... Habiendo dicho eso, los regalos (como el café gratis o las tarjetas de regalo de iTunes) siempre son divertidos. Pero creo que hay aquellos que necesitan reales que se beneficiarán más de su generosidad.