# coding: utf-8 import os import math from PIL import Image from fpdf import FPDF from flask import current_app from flask_login import current_user from tempfile import NamedTemporaryFile from functools import cache from webinterface.models.documentos import Documento from datetime import datetime, timedelta, date from PyPDF2 import PdfFileReader, PdfFileMerger from webinterface.models.gestion import Objetivo, Accion, Evidencia, Comision @cache def logoyencabezado(Nodo): uuid_nill = "00000000000000000000000000000000" responsable = Nodo.responsable while responsable.creado > 1: responsable = responsable.supervisor titulo = None logo = None docLogo = Documento.query.filter(Documento.hash==responsable.logo).one_or_none() if docLogo is not None: logoFile = docLogo.get_file() if logoFile is not None: logo = os.path.abspath(logoFile) docTitulo = Documento.query.filter(Documento.hash==responsable.titulo).one_or_none() if docTitulo is not None: tituloFile = docTitulo.get_file() if tituloFile is not None: titulo = os.path.abspath(tituloFile) return (logo, titulo) def ReportePDF(Archivo, Nodo, Fini=None, Ffin=None): logo, titulo = logoyencabezado(Nodo) maindoc = plantillaReporte(Titulo=Nodo.nombre, Logo=logo, Encabezado=titulo) maindoc.set_title(u"Reporte de Gestión: {}".format(Nodo.nombre)) maindoc.set_subject(Nodo.nombre) maindoc.set_author("iLab Gestion: {}".format(maindoc.serial)) maindoc.set_creator(current_user.ascii_nombrecompleto) Horachilena=datetime.today() - timedelta(hours=4) Horachilenastr = Horachilena.strftime('Generado el %d/%m/%Y a las %H horas') if isinstance(Fini,date) and isinstance(Ffin, date) and Fini < Ffin: maindoc.Tapa('Reporte de Gestión desde {:%d/%m/%Y} hasta {:%d/%m/%Y}.'.format(Fini, Ffin), Linea2=Nodo.nombre, Linea3=Horachilenastr, Logo=True) else: maindoc.Tapa('Reporte de Gestión', Linea2=Nodo.nombre, Linea3=Horachilenastr, Logo=True) maindoc, _, _ = ReporteNodo(maindoc, Nodo, True, Fini, Ffin) paginas_en_blanco = maindoc.paginas_en_blanco anexos_pdf = maindoc.anexospdf paginas_reporte = maindoc.page_no() current_app.logger.debug(u'PDF original tiene {} páginas'.format(paginas_reporte)) with NamedTemporaryFile() as tmp: maindoc.output(name=tmp.name, dest='F') merger = PdfFileMerger(strict=False) pagina = 0 while pagina < paginas_reporte: if pagina not in paginas_en_blanco: merger.append(tmp.name, pages=(pagina, pagina+1)) pagina = pagina + 1 else: archivo_pdf, largo = anexos_pdf.pop(0) merger.append(archivo_pdf) pagina = pagina + largo merger.write(Archivo) merger.close() return "reporte_gestion-{}-{}.pdf".format(Nodo.id, maindoc.serial) def ListaActaPDF(Archivo, Acta): logo, titulo = logoyencabezado(Acta.objetivo) maindoc = plantillaReporte(Titulo='Acta {}: {}'.format(Acta.secuencia, Acta.objetivo.nombre), Logo=logo, Encabezado=titulo) maindoc.add_page() maindoc.PutLogoCenter() maindoc.Titulo1(u'{} - Acta {}'.format(Acta.objetivo.nombre, Acta.secuencia), align='C', newpage=False) maindoc.Titulo2(u"Listado de Asistentes", align='C', Tight=True) maindoc.Titulo2(u"Fecha: {}".format(Acta.horaini.strftime('%d/%m/%Y')), align='C', Tight=True) count = 0 w = maindoc.AnchoFirma(Acta.asistentes) for asistente in Acta.asistentes: if count>0 and count % 11 == 0: maindoc.add_page() maindoc.ln(25) count = count + 1 # maindoc.ln(5) maindoc.Firma("{}) {}".format(count, asistente),Ancho=w) maindoc.output(name=Archivo, dest='F') return "Lista acta {}-{} {}.pdf".format(Acta.secuencia, Acta.objetivo.nombre, maindoc.serial) def ActaPDF(Archivo, Acta): logo, titulo = logoyencabezado(Acta.objetivo) maindoc = plantillaReporte(Titulo='Acta {}: {}'.format(Acta.secuencia, Acta.objetivo.nombre), Logo=logo, Encabezado=titulo) maindoc = ReporteActa(maindoc, Acta) paginas_en_blanco = maindoc.paginas_en_blanco anexos_pdf = maindoc.anexospdf paginas_reporte = maindoc.page_no() current_app.logger.debug(u'PDF original tiene {} páginas'.format(paginas_reporte)) with NamedTemporaryFile() as tmp: maindoc.output(name=tmp.name, dest='F') merger = PdfFileMerger(strict=False) pagina = 0 while pagina < paginas_reporte: if pagina not in paginas_en_blanco: merger.append(tmp.name, pages=(pagina, pagina+1)) pagina = pagina + 1 else: archivo_pdf, largo = anexos_pdf.pop(0) merger.append(archivo_pdf) pagina = pagina + largo merger.write(Archivo) merger.close() return "acta {}-{} {}.pdf".format(Acta.secuencia, Acta.objetivo.nombre, maindoc.serial) def ReporteActa(documento, Acta): documento.add_page() documento.PutLogoCenter() documento.Titulo1(u'Acta {}'.format(Acta.secuencia), align='C', newpage=False) documento.Titulo1(Acta.objetivo.nombre, align='C', newpage=False) documento.LugaryFecha(Acta.lugar, Acta.horaini, Acta.horafin) documento.Asistentes(Acta.asistentes) documento.TituloParrafo(u'Temas', Acta.temas) if len(Acta.desarrollo): documento.TituloParrafo(u'Desarrollo', Acta.desarrollo) if len(Acta.acuerdos): documento.TituloParrafo(u'Acuerdos', Acta.acuerdos) links = [] fotos = [] pdfs = [] evidencias = 0 for evidencia in Acta.anexos: if evidencia.documento.nombre[:7] == 'http://' or evidencia.documento.nombre[:8] == 'https://': # current_app.logger.debug(u'Link detectado: {}'.format(evidencia.documento.nombre)) links.append((evidencia.documento.nombre, evidencia.documento.descripcion)) evidencias = evidencias + 1 elif evidencia.documento.tamano > 0: nombre, extension = os.path.splitext(evidencia.documento.nombre.lower()) if extension in ['.jpg', '.jpeg', '.png']: evidencias = evidencias + 1 fotos.append(evidencia) if extension in ['.pdf']: evidencias = evidencias + 1 pdfs.append(evidencia) if evidencias > 0: if len(links) > 0: documento.Titulo2('Anexos') for link in links: documento.Link(link) if len(fotos) > 0: documento.FotoEvidencia(fotos) if len(pdfs) > 0: largo = 0 for evidencia in pdfs: archivo = PdfFileReader(open(evidencia.documento.get_file(), "rb")) largo = largo + archivo.getNumPages() documento.anexospdf = (evidencia.documento.get_file(), archivo.getNumPages()) documento.pagina_en_blanco(largo) return documento def ReporteNodo(documento, Nodo, Recursive=True, Fini=None, Ffin=None, anexoi=0, anexos={}): documento.Titulo1(Nodo.nombre) if isinstance(Fini,date) and isinstance(Ffin, date) and Fini < Ffin: rango = True DTini = datetime(Fini.year, Fini.month, Fini.day, 0, 0, 0) DTfin = datetime(Ffin.year, Ffin.month, Ffin.day, 23, 59, 59) else: rango = False if Nodo.sub_HDS < 1: documento.Item(Sujeto='Dedicación al objetivo:',Predicado= u'{} Horas cronológicas'.format(round(Nodo.sub_horas,1)), Ancho=55) else: documento.Item(Sujeto='Dedicación al objetivo:',Predicado= u'{} Horas cronológicas ({} Horas de dedicación semanal)'.format(round(Nodo.sub_horas,1), Nodo.sub_HDS), Ancho=55) if len(Nodo.descripcion)>0: documento.Titulo3("Descripción del Objetivo") documento.Parrafo(Nodo.descripcion) # indicadores eactas = 0 for Acta in Nodo.actasr: if rango and (Acta.horaini < DTini or Acta.horaini > DTfin): continue if eactas == 0: documento.Titulo2("Actas") documento.Indicador(Glosa="Acta/Lugar", vIni="Fecha", vAct="Hora", vFin="Fin", Titulo=True, ancho=25) eactas = eactas + 1 documento.Indicador(Glosa="Acta {}: {}".format(Acta.secuencia, Acta.lugar), vIni=Acta.horaini.strftime('%d/%m/%Y'), vAct=Acta.horaini.strftime('%H:%M'), vFin=Acta.horafin.strftime('%H:%M'), ancho=25) # indicadores eind = 0 for Indicador in Nodo.indicadores: if eind == 0: documento.Titulo2("Indicadores") documento.Indicador(Glosa="Indicador", vIni="Inicial", vAct="Actual", vFin="Meta", Titulo=True) eind = eind + 1 documento.Indicador(Glosa=Indicador.nombre, vIni=Indicador.inicial, vAct=Indicador.valor, vFin=Indicador.meta) # Actividades if Recursive is True: anexos = {} eact = 0 for Accion in Nodo.iactividades: if rango and (Accion.fecha < Fini or Accion.fecha > Ffin): continue if eact == 0: documento.Titulo2("Actividades Realizadas", border='b', Tight=False) eact = eact + 1 documento.Titulo2(u"Actividad {}: {}".format(eact, Accion.nombre)) documento.Item(Sujeto='Fecha:',Predicado= u'{}'.format(Accion.fecha.strftime('%d/%m/%Y')), Ancho=20) if Accion.dedicacion < 26: documento.Item(Sujeto='Dedicación:',Predicado= u'{} Horas cronológicas'.format(Accion.dedicacion), Ancho=30) else: documento.Item(Sujeto='Dedicación:',Predicado= u'{} Horas cronológicas ({} Horas de dedicación semanal)'.format(Accion.dedicacion, round(Accion.dedicacion/26,2)), Ancho=30) if len(Accion.descripcion)>0: documento.Titulo3(u"Descripción de la Actividad") documento.Parrafo(Accion.descripcion) evidencias = 0 links = [] for evidencia in Accion.evidencias: if evidencia.documento.nombre[:7] == 'http://' or evidencia.documento.nombre[:8] == 'https://': links.append((evidencia.documento.nombre, evidencia.documento.descripcion)) elif evidencia.documento.tamano > 0: nombre, extension = os.path.splitext(evidencia.documento.nombre.lower()) if extension in ['.jpg', '.jpeg', '.png', '.pdf']: evidencias = evidencias + 1 if evidencias > 0 or len(links) > 0: documento.Titulo3('Evidencias') if len(links)>0: for link in links: documento.Link(link) if evidencias > 0: if anexoi > 25: v1 = chr(ord('A') + int(anexoi/26) - 1) v2 = chr(ord('A') + anexoi%26) v = '{}{}'.format(v1,v2) else: v = chr(ord('A') + anexoi) anexoi = anexoi + 1 anexos[v] = Accion documento.Parrafo(u'Ver Anexo {}.'.format(v)) if Recursive is True: for hijo in Nodo.hijos: documento, anexoi, anexos = ReporteNodo(documento, hijo, Recursive=False, Fini=Fini, Ffin=Ffin, anexoi=anexoi, anexos=anexos) else: return (documento, anexoi, anexos) eacta = 0 for Acta in Nodo.actasr: if rango and (Acta.horaini < DTini or Acta.horaini > DTfin): continue if eacta == 0: eacta = 1 documento.Tapa('Anexo Actas') documento = ReporteActa(documento, Acta) if Recursive is True: for hijo in Nodo.hijos: for Acta in hijo.actas: if rango and (Acta.horaini < DTini or Acta.horaini > DTfin): continue if eacta == 0: eacta = 1 documento.Tapa('Anexo Actas') documento = ReporteActa(documento, Acta) for letra, anexo in anexos.items(): documento.Tapa('Anexo {}'.format(letra)) fotos = [] pdfs = [] for evidencia in anexo.evidencias: nombre, extension = os.path.splitext(evidencia.documento.nombre.lower()) if extension in ['.jpg', '.jpeg', '.png']: fotos.append(evidencia) if extension in ['.pdf']: pdfs.append(evidencia) if len(fotos) > 0: documento.FotoEvidencia(fotos) if len(pdfs) > 0: largo = 0 for evidencia in pdfs: archivo = PdfFileReader(open(evidencia.documento.get_file(), "rb")) largo = largo + archivo.getNumPages() documento.anexospdf = (evidencia.documento.get_file(), archivo.getNumPages()) documento.pagina_en_blanco(largo) return (documento, anexoi, anexos) class plantillaReporte(FPDF): def __init__(self, Titulo = None, Logo = None, Encabezado = None): super(plantillaReporte, self).__init__('P', 'mm', 'Letter') self.set_compression(True) self.add_font('dejavu', '', fname='/srv/font/DejaVuSerif.ttf', uni=True) self.add_font('dejavu', 'B', fname='/srv/font/DejaVuSerif-Bold.ttf', uni=True) self.add_font('dejavu', 'I', fname='/srv/font/DejaVuSerif-Italic.ttf', uni=True) self.add_font('dejavu', 'BI', fname='/srv/font/DejaVuSerif-BoldItalic.ttf', uni=True) self.__titulo = Titulo self.__ancho = 215.9 # 190 / 185 self.__alto = 279.4 # 125 / 120 self.__columna = 90 self.__limiteT2 = 0.8 * self.__alto self.__limiteT3 = 0.85 * self.__alto self.__codigo = datetime.today().strftime('%Y%m%d%H.%M%S') self.__blanks = [] self.__pdf = [] self.__subtitulo = None self.__h1 = 14 self.__h2 = 12 self.__h3 = 10 self.__logo = Logo self.__encabezado = Encabezado # self.__fecha = datetime.today().strftime('%d/%m/%Y a las %H horas') # self.__titulos = [] # self.__ptitulos = [] # Encabezado def header(self): if self.__titulo is not None and self.page_no() > 1: self.set_y(1) self.cell(0, 5+self.__h1, u'', border='B', ln=1, align='C') if self.__encabezado is not None: imLogo = Image.open(os.path.abspath(self.__encabezado)) w, h = imLogo.size ancho = self.__h2 * w / h _, extension = os.path.splitext(self.__logo) self.image(self.__encabezado, x=10, y=6, w=ancho, type=extension[1:]) else: self.set_font('dejavu', 'B', self.__h2) self.set_y(5) self.cell(110, self.__h1, self.__titulo, border=0, ln=0, align='L') # if self.__subtitulo is not None: # self.cell(0, 10, self.__subtitulo, border=0, ln=0, align='R') self.ln(self.__h2) # Pie de Página def footer(self): # Position at 1.5 cm from bottom if self.page_no() > 1: self.set_y(-15) self.cell(0, 8, u'', border='T', ln=1, align='C') self.set_y(-15) self.set_font('dejavu', '', 3) self.cell(60, self.__h3, u'Versión: {}'.format(self.__codigo), border=0, ln=0, align='L') self.set_font('dejavu', 'I', self.__h3) self.cell(0, self.__h3, u'Página {}'.format(self.page_no()), border=0, ln=0, align='R') def pagina_en_blanco(self, Num = 1): for i in range(Num): self.Tapa(u"Esta página fue dejada intencionalmente en blanco") self.__blanks.append(self.page_no()-1) @property def anexospdf(self): return self.__pdf @anexospdf.setter def anexospdf(self, valor): self.__pdf.append(valor) @property def paginas_en_blanco(self): return self.__blanks @property def serial(self): return self.__codigo def Tapa(self, Titulo, Linea2=None, Linea3=None, Logo=False): if self.page_no() > 1: self.__subtitulo = Titulo self.add_page() if self.__logo is not None and Logo is True: self.ln(self.__h1) self.ln(self.__h2) self.PutLogoCenter() if Linea2 or Linea3: self.set_y((self.__alto-40)/2) else: self.set_y((self.__alto-20)/2) self.set_font('dejavu', 'B', self.__h1+2) self.multi_cell(0, self.__h1, Titulo, border=0, align='C') if Linea2 is not None: self.set_font('dejavu', 'B', self.__h1) self.multi_cell(0, self.__h2, Linea2, border=0, align='C') if Linea3 is not None: self.set_font('dejavu', '', self.__h2) self.multi_cell(0, self.__h3, Linea3, border=0, align='C') def PutLogoCenter(self): if self.__logo is not None: yini = self.get_y() imLogo = Image.open(os.path.abspath(self.__logo)) w, h = imLogo.size y = self.__columna * h / w xLogo = (self.__ancho - self.__columna) / 2 _, extension = os.path.splitext(self.__logo) # current_app.logger.debug(u'Logo {} {} {} {} {}'.format(xLogo,w,h,y,extension)) self.image(self.__logo, x=xLogo, y=yini, w=self.__columna, type=extension[1:]) yfin = yini + y self.set_y(yfin) def Titulo1(self, Titulo, align='L', newpage=True): if newpage: self.add_page() # self.__titulos.append(Titulo) # self.__ptitulos.append(self.page_no()) self.set_font('dejavu', 'B', self.__h1) self.multi_cell(0, self.__h1, Titulo, border=0, align=align) # self.cell(0, self.__h1, Titulo, border=0, ln=0, align=align) # self.ln(self.__h1) def Titulo2(self, Titulo, border=0, align='L', Tight=True): if not Tight: self.ln(self.__h3) if self.get_y() > self.__limiteT2: self.add_page() self.set_font('dejavu', 'B', self.__h2) self.multi_cell(0, self.__h2, Titulo, border=0, align=align) # self.cell(0, self.__h2, Titulo, border=border, ln=0, align=align) # self.ln(self.__h2) def Titulo3(self, Titulo): if self.get_y() > self.__limiteT3: self.add_page() self.set_font('dejavu', 'B', self.__h3) self.multi_cell(0, self.__h3, Titulo, border=0, align='L') # self.cell(0, self.__h3, Titulo, border=0, ln=0, align='L') # self.ln(self.__h3) def Parrafo(self, Texto): self.Normal() self.multi_cell(0, self.__h3, Texto, align='J') # self.ln(self.__h3) def Normal(self): self.set_font('dejavu', '', self.__h3) def LimpiaColordeFondo(self): self.set_fill_color(1, 1, 1) def ColordeFondo(self): self.set_fill_color(230, 230, 230) def TituloParrafo(self, Titulo, Parrafo): self.set_font('dejavu', 'B', self.__h2) self.cell(0, self.__h2, Titulo, border=0, ln=1, align='L') self.ColordeFondo() self.Normal() self.multi_cell(0, self.__h3, Parrafo, align='J', fill=True) self.ln(self.__h3) def LugaryFecha(self, lugar, horaini, horafin): self.ColordeFondo() self.set_font('dejavu', 'B', self.__h2) self.cell(0, self.__h2, "Lugar", border=0, ln=1, align='L') self.set_font('dejavu', '', self.__h2) self.cell(0, self.__h2, lugar, border=0, ln=1, align='L', fill = True) self.set_font('dejavu', 'B', self.__h2) self.cell(67, self.__h2, 'Fecha', border=0, ln=0, align='L') self.cell(67, self.__h2, 'Inicio', border=0, ln=0, align='L') self.cell(61, self.__h2, u'Término', border=0, ln=1, align='L') self.set_font('dejavu', '', self.__h2) self.cell(61, self.__h2, horaini.strftime('%d/%m/%Y'), border=0, ln=0, align='C', fill = True) self.cell(6, self.__h2, '', border=0, ln=0, align='L') self.cell(61, self.__h2, horaini.strftime('%H:%M'), border=0, ln=0, align='C', fill = True) self.cell(6, self.__h2, '', border=0, ln=0, align='L') self.cell(61, self.__h2, horafin.strftime('%H:%M'), border=0, ln=1, align='C', fill = True) def Asistentes(self, asistentes): self.ColordeFondo() self.set_font('dejavu', 'B', self.__h2) self.cell(0, self.__h2, "Convocados", border=0, ln=1, align='L') count = 0 for asistente in asistentes: self.set_font('dejavu', '', self.__h3) rcells = math.ceil(self.get_string_width(asistente)/61) if rcells == 1: w = 61 elif rcells == 2: w = 128 else: w = 195 if ((count + rcells) % 3 <= count % 3): self.set_font('dejavu', '', self.__h3) self.cell(w, self.__h3, asistente, border=0, ln=1, align='C', fill = True) else: self.set_font('dejavu', '', self.__h3) self.cell(w, self.__h3, asistente, border=0, ln=0, align='C', fill = True) self.cell(6, self.__h3, '', border=0, ln=0, align='L') count = count + rcells if count == 0: self.set_font('dejavu', '', self.__h3) self.cell(0, self.__h3, 'No existen convocados', border=0, ln=1, align='L') elif count % 3 != 0: self.ln(self.__h2) def Indicador(self, Glosa, vIni, vAct, vFin, Titulo = False, ancho=16): if Titulo: self.set_font('dejavu', 'B', self.__h3) else: self.set_font('dejavu', '', self.__h3) top = self.get_y() anchoglosa = 195 - 3*ancho self.multi_cell(anchoglosa, self.__h3, str(Glosa), border=1, align='J') bottom = self.get_y() if bottom < top: # si el final está en la siguiente página, partimos la celda desde arriba. top = 20 altura = bottom - top # 125-45 = 80 | 125-36 = 89 self.set_y(top) self.set_x(anchoglosa+10) # current_app.logger.debug(u'Indicador: top:{} bottom:{} altura:{} anchoglosa:{}'.format(top,bottom,altura,anchoglosa)) self.cell(ancho, altura, str(vIni), border=1, ln=0, align='C') self.cell(ancho, altura, str(vAct), border=1, ln=0, align='C') self.cell(ancho, altura, str(vFin), border=1, ln=1, align='C') self.set_y(bottom) def AnchoFirma(self, asistentes): w = 0 self.set_font('dejavu', '', self.__h1) for asistente in asistentes: w = max(w, self.get_string_width(asistente)) return w+10 def Firma(self, Sujeto, Ancho=80, Titulo=False): if Titulo: self.set_font('dejavu', 'B', self.__h1) else: self.set_font('dejavu', '', self.__h1) self.cell(Ancho, self.__h1, Sujeto , ln=0, align='L') self.cell(0 , self.__h1, '' , border='B', ln=1) def Item(self, Sujeto, Predicado, Ancho=80, borde=0, ln=0, alineacion='L'): self.set_font('dejavu', 'I', self.__h2) self.cell(Ancho, self.__h3, Sujeto, border=borde, ln=0, align=alineacion) self.set_font('dejavu', '', self.__h2) self.cell(0, self.__h3, Predicado, border=borde, ln=1, align=alineacion) def Link(self, linktupla): link, descripcion = linktupla self.set_font('dejavu', '', self.__h2) self.cell(35, self.__h3, u'Link Externo:', border=0, ln=0, align='L') self.set_text_color(r=0, g=0, b=255) if len(descripcion) > 60: self.cell(0, self.__h3, u"{}...".format(descripcion[:60]), border=0, ln=1, align='L', link=link) elif len(descripcion) > 0: self.cell(0, self.__h3, descripcion, border=0, ln=1, align='L', link=link) elif len(link) > 60: self.cell(0, self.__h3, u"{}...".format(link[:60]), border=0, ln=1, align='L', link=link) else: self.cell(0, self.__h3, link, border=0, ln=1, align='L', link=link) self.set_text_color(r=0, g=0, b=0) def FotoEvidencia(self, fotos): self.add_page() nfotos = len(fotos) filas = int(nfotos/2) sobran = nfotos % 2 seq = 0 self.set_font('dejavu', '', self.__h2) for fila in range(filas): primera = seq segunda = primera + 1 seq = seq + 2 # Obtenemos el tamaño de la imagen im1 = Image.open(os.path.abspath(fotos[primera].documento.get_file())) w1, h1 = im1.size im2 = Image.open(os.path.abspath(fotos[segunda].documento.get_file())) w2, h2 = im2.size #Calculamos la altura a medio espacio y1 = self.__columna * h1 / w1 y2 = self.__columna * h2 / w2 # Vemos si tenemos suficiente espacio en la hoja para poner ambas imagenes ymax = max(y1, y2) if ymax + self.get_y() > self.__limiteT3: self.add_page() # Guardamos la posición inicial antes de pegar las imagenes y sus captions posicionYinicial = self.get_y() ## Primera imagen yImagenCentrada = posicionYinicial + ymax - y1 xColumna1 = 10 _, extension = os.path.splitext(fotos[primera].documento.nombre) self.image(fotos[primera].documento.get_file(), x=xColumna1, y=yImagenCentrada, w=self.__columna, type=extension[1:]) yImagenCentrada = posicionYinicial + ymax - y2 xColumna2 = 25 + self.__columna _, extension = os.path.splitext(fotos[segunda].documento.nombre) self.image(fotos[segunda].documento.get_file(), x=xColumna2, y=yImagenCentrada, w=self.__columna, type=extension[1:]) # Captions de las imagenes self.set_x(10) self.set_y(posicionYinicial + ymax + self.__h3) self.multi_cell(w=self.__columna, h=self.__h3, txt=fotos[primera].documento.descripcion or fotos[primera].documento.nombre, border=0, align='C') y1 = self.get_y() self.set_y(posicionYinicial + ymax + self.__h3) self.set_x(xColumna2) self.multi_cell(w=self.__columna, h=self.__h3, txt=fotos[segunda].documento.descripcion or fotos[segunda].documento.nombre, border=0, align='C') y2 = self.get_y() # Dejamos el cursor bajo ambos captions self.set_y(max(y1,y2)) self.ln(self.__h3) if sobran > 0: seq = nfotos-1 im1 = Image.open(os.path.abspath(fotos[seq].documento.get_file())) w1, h1 = im1.size y1 = self.__columna * h1 / w1 if y1 + self.get_y() > self.__limiteT2: self.add_page() # Guardamos la posición inicial antes de pegar las imagenes y sus captions posicionYinicial = self.get_y() xColumna1 = 10 + self.__columna / 2 _, extension = os.path.splitext(fotos[seq].documento.nombre) self.image(fotos[seq].documento.get_file(), x=xColumna1, y=posicionYinicial, w=self.__columna, type=extension[1:]) self.set_y(posicionYinicial + y1 + self.__h3) self.set_x(xColumna1) self.multi_cell(w=self.__columna, h=self.__h3, txt=fotos[seq].documento.descripcion or fotos[seq].documento.nombre, border=0, align='C')