Divida, combine y gire documentos PDF en Python con borb

En esta guía, usaremos borb, una biblioteca PDF de Python puro para dividir, fusionar y rotar páginas de documentos PDF en Python, ¡con ejemplos prácticos!

Introducción

El Formato de documento portátil (PDF) no es un formato WYSIWYG (Lo que ves es lo que obtienes). Fue desarrollado para ser independiente de la plataforma, independiente del sistema operativo subyacente y los motores de renderizado.

Para lograr esto, el PDF se construyó para interactuar a través de algo más parecido a un lenguaje de programación y se basa en una serie de instrucciones y operaciones para lograr un resultado. De hecho, PDF está basado en un lenguaje de secuencias de comandos: Posdata, que fue el primer lenguaje de descripción de página independiente del dispositivo.

En esta guía, usaremos borracho, una biblioteca de Python dedicada a leer, manipular y generar documentos PDF. Ofrece un modelo de bajo nivel (que le permite acceder a las coordenadas y el diseño exactos si elige usarlos) y un modelo de alto nivel (donde puede delegar los cálculos precisos de márgenes, posiciones, etc. a un administrador de diseño) .

En esta guía, veremos cómo dividir y fusionar documentos PDF en Python usando borb, también veremos cómo rotar páginas en un documento PDF.

Dividir y fusionar documentos PDF es la base para muchos casos de uso:

  • Procesar una factura (no necesita los términos y condiciones para poder eliminar esas páginas)
  • Agregar una carta de presentación a los documentos (un informe de prueba, una factura, material promocional)
  • Agregación de resultados de pruebas de fuentes heterogéneas
  • Etc.

Instalando borb

borb puede descargarse desde la fuente en GitHub, o instalarse a través de pip:

1
$ pip install borb

Dividir un PDF usando borb

Para demostrar esto, necesitará un PDF con algunas páginas.
Comenzaremos creando un PDF de este tipo usando borb. Este paso es opcional, por supuesto, puede simplemente usar un PDF que tenga por ahí:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
from borb.pdf.canvas.color.color import HexColor
from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout
from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout
from borb.pdf.canvas.layout.text.paragraph import Paragraph
from borb.pdf.document import Document
from borb.pdf.page.page import Page
from borb.pdf.pdf import PDF
from decimal import Decimal

def create_document(heading_color: HexColor = HexColor("0b3954"), 
                    text_color: HexColor = HexColor("de6449"),
                    file_name: str = "output.pdf"):

    d: Document = Document()

    N: int = 10
    for i in range(0, N):
    
        # Create a new Page, and append it to the Document
        p: Page = Page()
        d.append_page(p)
        
        # Set the PageLayout of the new Page
        l: PageLayout = SingleColumnLayout(p)
        
        # Add the paragraph to identify the Page
        l.add(Paragraph("Page %d of %d" % (i+1, N),
                        font_color=heading_color,
                        font_size=Decimal(24)))
                        
        # Add a Paragraph of dummy text                        
        l.add(Paragraph("""
                        Lorem Ipsum is simply dummy text of the printing and typesetting industry. 
                        Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, 
                        when an unknown printer took a galley of type and scrambled it to make a type specimen book. 
                        It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. 
                        It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, 
                        and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
                        """,
                        font_color=text_color))
    
    # Persist the Document to disk
    with open(file_name, "wb") as pdf_out_handle:
        PDF.dumps(pdf_out_handle, d)

Este código de ejemplo genera un documento PDF que consta de 10 páginas:

  • Cada página comienza con "Página x de 10". Esto hará que sea más fácil identificar las páginas más adelante.
  • Cada página contiene 1 párrafo de texto.

División de documentos PDF en Python

Ahora dividamos este PDF. Comenzaremos dividiéndolo en dos, la primera mitad contiene las primeras 5 páginas y la segunda mitad contiene las páginas restantes:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def split_half_half():

  # Read PDF
  with open("output.pdf", "rb") as pdf_file_handle:
    input_pdf = PDF.loads(pdf_file_handle)

  # Create two empty PDFs to hold each half of the split
  output_pdf_001 = Document()
  output_pdf_002 = Document()

  # Split
  for i in range(0, 10):
    if i < 5:
      output_pdf_001.append_page(input_pdf.get_page(i))
    else:
      output_pdf_002.append_page(input_pdf.get_page(i))

  # Write PDF
  with open("output_001.pdf", "wb") as pdf_out_handle:
    PDF.dumps(pdf_out_handle, output_pdf_001)

  # Write PDF
  with open("output_002.pdf", "wb") as pdf_out_handle:
    PDF.dumps(pdf_out_handle, output_pdf_002)

Hemos extraído las primeras 5 páginas en un nuevo ‘Documento’, y las siguientes 5 páginas en un segundo nuevo ‘Documento’, dividiendo efectivamente el original en dos entidades más pequeñas.

Esto se hace fácil a través del método get_page(), ya que su tipo de devolución se puede usar directamente con append_page().

Puede verificar los archivos PDF resultantes para verificar que el código funcione según lo previsto:

splitting a pdf document in python

spllitting a pdf document in python

El primer documento termina en la página 5 y el segundo comienza en la página 6.

¡También podemos dividirlo según otros criterios! En el siguiente ejemplo, dividiremos el PDF colocando todas las páginas impares en un PDF y las páginas pares en otro:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def split_even_odd():

  # Read PDF
  with open("output.pdf", "rb") as pdf_file_handle:
    input_pdf = PDF.loads(pdf_file_handle)
  
  # Rreate two empty PDFs to hold each half of the split
  output_pdf_001 = Document()
  output_pdf_002 = Document()

  # Split
  for i in range(0, 10):
    if i % 2 == 0:
      output_pdf_001.append_page(input_pdf.get_page(i))
    else:
      output_pdf_002.append_page(input_pdf.get_page(i))

  # Write PDF
  with open("output_001.pdf", "wb") as pdf_out_handle:
    PDF.dumps(pdf_out_handle, output_pdf_001)

  # Write PDF
  with open("output_002.pdf", "wb") as pdf_out_handle:
    PDF.dumps(pdf_out_handle, output_pdf_002)

Puede verificar que los documentos PDF resultantes representan la división antes mencionada:

split pdf on odd pages

split pdf on odd pages

Fusión de documentos PDF en Python

Para trabajar los siguientes ejemplos necesitaremos dos PDF. Usemos el código anterior para generarlos si aún no tiene alguno:

1
2
create_document(HexColor("247B7B"), HexColor("78CDD7"), "output_001.pdf")
create_document(file_name="output_002.pdf")

La intuición que se usa para dividir es bastante similar a la fusión; sin embargo, podemos agregar documentos completos a otros documentos, no solo páginas. Sin embargo, a veces es posible que desee dividir un documento (cortar la última página) antes de fusionarlo con otro.

Podemos fusionarlos por completo (concatenando ambos PDF), pero también podemos simplemente agregar algunas páginas del primer PDF al segundo si lo preferimos de esa manera, usando la función append_page() como antes.

Comencemos concatenándolos por completo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
def concatenate_two_documents():

  # Read first PDF
  with open("output_001.pdf", "rb") as pdf_file_handle:
    input_pdf_001 = PDF.loads(pdf_file_handle)
  
  # Read second PDF
  with open("output_002.pdf", "rb") as pdf_file_handle:
    input_pdf_002 = PDF.loads(pdf_file_handle)
  
  # Build new PDF by concatenating two inputs
  output_document = Document()
  output_document.append_document(input_pdf_001)
  output_document.append_document(input_pdf_002)
  
  # Write PDF
  with open("output.pdf", "wb") as pdf_out_handle:
    PDF.dumps(pdf_out_handle, output_document)

Este código debería resultar en:

fusión de documentos pdf en python con borb

Rotación de páginas en documentos PDF en Python

Una página en un documento PDF se puede girar en cualquier múltiplo de 90 grados. Este tipo de operación le permite cambiar fácilmente entre el modo horizontal y vertical.

En el siguiente ejemplo, rotará una página de uno de los PDF de entrada que creamos anteriormente:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def rotate_first_page():
  # Read PDF
  with open("output_001.pdf", "rb") as pdf_file_handle:
    input_pdf_001 = PDF.loads(pdf_file_handle)

  # Rotate page
  input_pdf_001.get_page(0).rotate_left()  
  
  # Write PDF to disk
  with open("output.pdf", "wb") as pdf_out_handle:
    PDF.dumps(pdf_out_handle, input_pdf_001)

El PDF resultante se ve así:

rotación de páginas de documentos pdf en python

Conclusión

En esta guía, hemos echado un vistazo a cómo fusionar y dividir documentos PDF. También hemos modificado un PDF existente rotando algunas de sus páginas.

Licensed under CC BY-NC-SA 4.0