Los proyectos de arquitectura son documentos de una complejidad bastante amplia.

Esa complejidad se magnifica debido al origen de los documentos que hay que incluir en nuestros proyectos: memoria, cálculo de estructuras, pliego de condiciones, presupuesto, anejos como los del estudio de gestión de residuos, la normativa de obligado cumplimiento, etc. Cada documento suele, casi siempre, tener un origen distinto, incluso cuando empleemos software para su desarrollo.

En consecuencia, darle al proyecto un aspecto coherente es, en ocasiones, una labor, cuando menos, «intensa» 😊

Por mi parte, una de las labores que suelo afrontar es la homogeneización de las subportadas de los distintos documentos que intervienen: memoria, planos, normativa, estudio de gestión de residuos, de seguridad, etc.

En mi caso, lo que suelo hacer es, en documento aparte, compilar cada una de estas portadas de subdocumento que tienen un origen distinto para, posteriormente, introducirla en el lugar adecuado a la hora de montar el documento final. Parto, en consecuencia, de un único documento .pdf con todas las portadas y, lo que suelo hacer es dividirlo en páginas sueltas para, posteriormente, incluir dichas páginas en su ubicación definitiva dentro del documento final.

Independientemente de los criterios de fijación de nombre de mis archivos .pdf, comentar que, como se puede deducir de la imagen superior, he imprimido todas las portadas de las secciones del proyecto en el documento con nombre ‘20220306 – 02 – Portadas secciones.AA.pdf’. Ahora, toca separar cada página en un documento diferente. Otra opción hubiera sido, desde el procesador de textos, imprimir cada página en un archivo individual –laborioso–.

¿Qué hacer? ¡Python to the rescue!

Lo que he hecho, sencillamente, es pre-configurar un archivo con el mismo nombre del archivo a dividir, pero con extensión .div, esto es ‘20220306 – 02 – Portadas secciones.AA.div’. Es, simplemente, un archivo .tsv con distinta extensión. ¿El contenido? ¡Sencillo! La estructura es la siguiente:

nº de orden + tabulador + nombre de archivo + tabulador + página correspondiente

Ejemplo de esto, sería lo que se muestra a continuación una vez ejecutado el comando head:

Con esto sabemos que el archivo a procesar se llama ‘20220306 – 02 – Portadas secciones.AA.div’ y que permitirá subdividir en partes el archivo ‘20220306 – 02 – Portadas secciones.AA.pdf’. Leyendo de izquierda a derecha en el archivo .div: en primer lugar, se generará la memoria, cuyo nombre será ‘20220306 – 0100 – Memoria.AA.pdf’ y que se corresponde con la página 1 del archivo ‘20220306 – 02 – Portadas secciones.AA.pdf’ y, así, sucesivamente.

Si queréis acceder al repositorio, el código está en abierto en bitbucket.

# -*- coding: utf-8 -*-
#-------------------------------------------------------------------------------
# Name:        seccionamontaje.py
# Purpose:     Extraer páginas de archivos .pdf para generar portadas mediante
#              páginas individuales a través de un archivo .tsv de plantilla
#
# Author:      Pedro I. Hernández G. :: Arquitecto
#
# Created:     07/mar/2022
# Copyright:   (c) pedro 2021
# Licence:     MIT
#-------------------------------------------------------------------------------

__author__  = "Pedro I. Hernández G."
__version__ = "1.0.0"
__date__    = "07/mar/2022"

try:
    import csv
    import glob
    import sys
    import time
    try:
        import fitz  # More capabilities
        mupdf = True
    except:
        from PyPDF2 import PdfFileWriter, PdfFileReader
        mupdf = False
except:
    print("Falta alguna de las dependencias: PyPDF2 o PyMuPDF.")
    print("Instale alguna mediante alguna de las ordenes")
    print("\t'pip install PyPDF2'")
    print("\t'pip install PyMuPDF'")
    sys.exit(-1)


class Seccionamontaje():
    def __init__(self, tsv_file_to_load, **conf):
        self.pdf_file_to_divide = tsv_file_to_load[:-4] + '.pdf'
        data_to_append = []
        with open(tsv_file_to_load) as tsv_f:
            tsv_file = csv.reader(tsv_f, delimiter="\t")
            for line in tsv_file:
                if len(line) > 0:
                    data_to_append.append(line)

        self.ordered_data_to_append = sorted(data_to_append, key = lambda x: int(x[0]))
        self.do_division()

    def _herramienta(self):
        return 'PyMuPDF' if mupdf else 'PyPDF2'

    def do_division(self):
        print("\tArchivo a dividir: '{}'".format(self.pdf_file_to_divide))

        self.input_pdf = self._open(self.pdf_file_to_divide)

        for dta in self.ordered_data_to_append:
            output = self._set_output()
            self._save_output(output, dta[1], int(dta[2])-1)

        print("\tHecho :)")

    def _open(self, filename: str):
        try:
            if mupdf:
                return fitz.open(filename)
            else:
                return PdfFileReader(open(filename, "rb"))
        except:
            print("Error abriendo el archivo {} mediante {}".format(filename, self._herramienta()))
            print("Contacte con el soporte del software")
            print("Saliendo :(")
            sys.exit(-1)

    def _load_page(self, page_number: int):
        try:
            if mupdf:
                return self.input_pdf.load_page(page_number)
            else:
                return self.input_pdf.getPage(page_number)
        except:
            print("Error leyendo la pagina {} mediante {}".format(page_number, self._herramienta()))

    def _set_output(self):
        try:
            if mupdf:
                return fitz.open()
            else:
                return PdfFileWriter()
        except:
            print("Error creando un archivo .pdf nuevo mediante {}".format(self._herramienta()))

    def _save_output(self, new_pdf, new_pdf_name, page_nr):
        try:
            if mupdf:
                new_pdf.insert_pdf(self.input_pdf, \
                                   from_page=page_nr, \
                                   to_page=page_nr)
                new_pdf.save(new_pdf_name)
            else:
                new_pdf.addPage(self._load_page(page_nr))
                with open (new_pdf_name, "wb") as output_stream:
                    new_pdf.write(output_stream)
        except:
            print("\t\tError escribiendo '{}' con {}".format(new_pdf_name, self._herramienta()))


class Presenta():
    def __init__(self):
        self.info = "Generador de archivos de portada de secciones de proyecto."
        self.version = "v.{} ({})".format(__version__, __date__)
        self.author = "© {}".format(__author__)

    def presenta(self):
        print(self.info)
        print(self.version, end=" ")
        print(self.author, end="\n\n")


def main():
    pr = Presenta()
    pr.presenta()
    print("Analizando...")
    files = glob.glob('*.div')
    if len(files) > 0:
        print("Generando...")
        for file in files:
            start = time.time()
            sm = Seccionamontaje(file)
            end = time.time()
            print("Total {} s.".format(round(end - start, 3)))
    else:
        print("No se han encontrado archivos '.div' en la ruta actual.")

if __name__ == "__main__":
    main()

Realizada la preconfiguración y creado el archivo .div, no queda más que ejecutar el código mediante el comando siguiente:

python seccionamontaje.py

Como se puede apreciar, hemos hecho uso de un entorno virtual para la ejecución, donde el único requisito previo es tener instalado el paquete PyPDF2. El software también funciona con el paquete PyMuPDF.

Resultado final

Como se puede apreciar, se ha procedido a realizar la división del archivo según lo previsto en el archivo de configuración .div. El siguiente paso será unir todo en un único archivo… ¡para otra entrada! 😂

…y con esto, ponemos fin a una entrada un poco más técnica… 😊 En vuestro caso, ¿cómo afrontáis la separación de subsecciones de vuestros proyectos? ¿Imprimís las páginas de separación una a una? ¿Cada documento ya tiene su portada correspondiente y, después, lo único que hacéis es unirlos?

Deja un comentario