def gerarPDF(qtd_img, Tamanho, qtd_Arq, diretorio): pdf = FPDF(orientation='P', format='A4', unit=u'mm') pdf.set_font(u'Arial', size=18) pdf.set_line_width(0.1) # evita quebra automatica da pagina, ao chegar perto da borda inferior pdf.set_auto_page_break(False) pdf.set_margins(8, 8) pdf.add_page() pdf.text(60, 50, txt=u'Relatório de Contagem de Imagens') pdf.ln("") pdf.set_font_size(size=10) pdf.text(10, 60, txt=u'Total de Imagens = %s' %qtd_img) pdf.text(80, 60, txt=u'Espaço Ocupado = %s' %Tamanho) pdf.text(150, 60, txt=u'Total de Arquivos = %s' %qtd_Arq) pdf.text(10, 70, txt=u'Data = %s às %s' %(datetime.datetime.now().date().__format__(u'%d/%m/%Y'), datetime.datetime.now().time().__format__(u'%H:%M:%S'))) pdf.ln("") pdf.text(10, 80, txt=u'Diretório Raiz= %s' %diretorio) pdf.output(u'./relatório.pdf', u'F') # gerarPDF(0,0,0,0)
def create_participation_cert(uuid, name, author, journal): pdf = FPDF() pdf.add_page() pdf.set_margins(10, 15, 60) pdf.image(settings.STATIC_ROOT + "/pdf/ref_publication_cert.jpg", 0, 0, 210) pdf.add_font('Arial', '', settings.STATIC_ROOT + '/pdf/arial.ttf', uni=True) pdf.set_font('Arial', '', 20) pdf.cell(0, 50, ln=1) pdf.set_font('Arial', '', 32) pdf.cell(0, 20, ln=1) pdf.cell(0, 6, str(journal), ln=1, align="C") pdf.set_font_size(16) pdf.cell(0, 20, ln=1) pdf.cell(0, 6, author, ln=1, align="C") pdf.cell(0, 20, ln=1) pdf.cell(0, 6, "Научная статья:", ln=1, align="C") pdf.cell(0, 6, name, ln=1, align="C") pathlib.Path(settings.MEDIA_ROOT + '/pdf/participation_cert').mkdir( parents=True, exist_ok=True) pdf.output( settings.MEDIA_ROOT + "/pdf/participation_cert/participation_cert_" + str(uuid) + ".pdf", 'F') return "/pdf/participation_cert/participation_cert_" + str(uuid) + ".pdf"
def create_publication_cert(uuid, name, author, journal, publication_date, created_date): pdf = FPDF() pdf.add_page() pdf.set_margins(25, 15, 15) pdf.image(settings.STATIC_ROOT + "/pdf/logo.png", 25, 15, 50) pdf.add_font('Arial', '', settings.STATIC_ROOT + '/pdf/arial.ttf', uni=True) pdf.set_font('Arial', '', 8) pdf.set_draw_color(50, 50, 50) pdf.cell(90, 5, ln=1) pdf.cell(90) pdf.cell(0, 3, "АНС «СибАК» ИНН 5404255395 КПП 540201001", ln=1) pdf.cell(90) pdf.cell(0, 3, "Адрес: г.Новосибирск, ул. Красный проспект, 165, офис 4", ln=1) pdf.cell(90) pdf.cell(0, 3, "Телефон: 8-913-915-38-00", ln=1) pdf.cell(90) pdf.cell(0, 3, "Р/с 40703810029100000978 в ОАО АКБ \"АВАНГАРД\"", ln=1) pdf.cell(90) pdf.cell(0, 3, "к/с 3010181000000000201", ln=1) pdf.cell(90) pdf.cell(0, 3, "БИК 044525201", ln=1) pdf.set_font_size(16) pdf.cell(0, 30, "СПРАВКА", ln=1, align="C") pdf.set_font_size(12) pdf.cell(0, 6, created_date.strftime('%d.%m.%Y') + " No. 14362", ln=1, align="L") pdf.cell(0, 6, ln=1) pdf.cell(0, 6, author, ln=1, align="R") pdf.cell(0, 6, ln=1) spisok = [name, journal, publication_date.strftime('%d.%m.%Y')] pdf.multi_cell( 0, 6, "Издательство подтверждает, что Ваша статья «{}» \ принята для публикации в научном журнале «{}». \ Журнал будет опубликован на сайте издательства {}.".format(*spisok)) pdf.cell(0, 24, ln=1) pathlib.Path(settings.MEDIA_ROOT + '/pdf/publication_cert').mkdir( parents=True, exist_ok=True) pdf.output( settings.MEDIA_ROOT + "/pdf/publication_cert/publication_cert_" + str(uuid) + ".pdf", 'F') return "/pdf/publication_cert/publication_cert_" + str(uuid) + ".pdf"
def onGenPDF(self,event): im = Image.open(self.filename) h,w = im.size pdf = FPDF('P','pt',(h,w)) pdf.add_page() pdf.set_font('Courier','B') pdf.set_font_size(10) pdf.set_text_color(0,255,0) effective_page_width = pdf.w-pdf.l_margin pdf.multi_cell(effective_page_width,6,self.msg.encode('latin-1','ignore')) pdf.image(self.filename,0,0) pdf.output("report.pdf", "F") print 'done check files'
def test_emoji_glyph(tmp_path): pdf = FPDF() font_file_path = HERE / "DejaVuSans.ttf" pdf.add_font("DejaVuSans", fname=str(font_file_path)) pdf.set_font("DejaVuSans", size=64) pdf.add_page() pdf.multi_cell(0, txt="".join([chr(0x1F600 + x) for x in range(68)])) pdf.set_font_size(32) pdf.text(10, 270, "".join([chr(0x1F0A0 + x) for x in range(15)])) assert_pdf_equal(pdf, HERE / "fonts_emoji_glyph.pdf", tmp_path)
def target_to_pdf(self, target: Target, target_path: str): self.logger.debug("Creating PDF Report.") pdf = FPDF(orientation='P', unit='mm', format='A4') pdf.add_page() pdf.set_font("Arial", size=16) pdf.cell(200, 10, txt="Mangekyou Report", ln=1, align="C") pdf.set_font_size(12) pdf.image(target.face, x=10, w=50) pdf.cell(65) pdf.cell(200, 20, txt=f"Name: {target.name}", ln=1) pdf.cell(200, 10, txt="Profiles:", ln=1) for profile in target.profiles: pdf.cell(200, 20, txt=f"{profile.url}", ln=1) pdf.output(f"{target_path}/report.pdf")
def feed_to_pdf(self): """ This function converts current feed to PDF document :return: pdf - PDF document containing news feed """ pdf = FPDF() pdf.add_page() font_path = os.path.join(os.path.dirname(__file__), 'fonts', 'ttf', 'DejaVuSerifCondensed.ttf') pdf.add_font('DejaVu', '', font_path, uni=True) pdf.set_font('DejaVu', '', 14) pdf.set_margins(10, 10, 5) pdf.cell(w=0, h=5, txt=self.feed) pdf.ln() pdf.ln() for article in self.news: pdf.set_font_size(12) pdf.multi_cell(w=0, h=5, txt=f'Title: {article.title}') pdf.multi_cell(w=0, h=5, txt=f'Date: {article.date}') pdf.multi_cell(w=0, h=5, txt=f'Url: {article.url}') pdf.ln() images = self.download_images(article, self.img_path, self.news.index(article)) if len(images): if images[0]: pdf.image(images[0], w=30) pdf.ln() pdf.multi_cell(w=0, h=5, txt=article.description) pdf.ln() pdf.cell(w=0, h=5, txt=f'Links:') pdf.ln() for link in article.links: if link.type == 'image': if link.url: pdf.multi_cell(w=0, h=5, txt=f'[{link.id + 1}]: {link.url} ({link.type})') else: pdf.multi_cell(w=0, h=5, txt=f'[{link.id + 1}]: {link.alt} (invalid url or no image)' f'({link.type})') else: pdf.multi_cell(w=0, h=5, txt=f'[{link.id + 1}]: {link.url} ({link.type})') pdf.ln() pdf.ln() if self.verbose: self.logger.info('Feed was converted to PDF format') return pdf
def create_pdf_page(codes_array, start, stop, pdf=None): """creates a single pdf page from codes_array[start:stop] Arguments: codes_array {[list]} -- [list of codes] start {[int]} -- [starting index] stop {[int]} -- [stop index] Keyword Arguments: pdf {[filepath]} -- [path to pdf to be appended to] (default: {None = new one will be created}) """ if not pdf: pdf = FPDF(orientation='P', unit='mm', format='A4') pdf.set_font('Arial') pdf.set_font_size(16) pdf.set_margins(3, 3.5, 3) pdf.set_auto_page_break(False) pdf.add_page() # two rows i = start for y in range(3, 149, 145): # 4 per row for x in range(3, 157, 51): if i > stop: return offset = (x, y + 0.5) # ticket offset_padding = (offset[0] + 1.5, offset[1] + 1.5) pdf.set_xy(offset[0], offset[1]) pdf.set_fill_color(150, 10, 10) pdf.cell(51, 145, "", 1, 1, 'c', True) code = codes_array[i] image_tempfile = create_qr(code) pdf.image(image_tempfile.name, offset_padding[0], offset_padding[1], 48, 48, 'PNG') os.unlink(image_tempfile.name) image_tempfile.close() pdf.set_xy(offset_padding[0], offset[1] + 51) pdf.set_fill_color(10, 150, 10) pdf.cell(48, 6, str(code), 1, 1, 'C', True) pdf.set_xy(offset_padding[0], offset[1] + 58.5) pdf.cell(48, 85, fill=True) i += 1
def create_pdf_news(path, News): if os.path.isdir(path) is False: raise RssException("Error. It isn't a folder") path = os.path.join(path, "News.pdf") pdf = FPDF() try: pdf.add_font('DejaVuSans', '', 'DejaVuSans.ttf', uni=True) pdf.set_font("DejaVuSans") except RuntimeError: raise RssException("fonts file not found") pdf.alias_nb_pages() pdf.add_page() for item_news in News: text = item_news.news # remove links in the text and add pictures start = text.find(']', 0, len(text)) text = text[start + 1:] pdf.set_font_size(26) pdf.write(11, item_news.title + '\n\n') pdf.set_font_size(14) pdf.write(11, f"Date: {item_news.date}\n") this_dir = os.path.abspath(os.path.dirname(__file__)) sys.path.append(this_dir) if len(item_news.links) > 0: try: pdf.image(f'{this_dir}/images/{correct_title(item_news.title)}.jpg', w=75, h=75) except RuntimeError: pass pdf.write(10, "\n") pdf.write(10, text + "\n\n\n\n") pdf.output(path, 'F') try: pdf.output(path, 'F') except FileNotFoundError: raise RssException("Error. No such folder") print("file News.pdf created")
def _create_license_page(self, pdf: FPDF, entry: LicenseReportEntry, unaccepted_packages: Set[str]): logging.debug(" generating page for %s", entry.package) pdf.add_page() pdf.set_font(_FONT) pdf.set_font_size(_NORMAL_SIZE) pdf.cell(0, _LINE_SIZE_MM, txt="Package: %s" % entry.package, ln=_NEXT_LINE) license_type_line = "License Type: %s" % entry.license_name if entry.package in unaccepted_packages: license_type_line += " (** Unacceptable **)" pdf.cell(0, _LINE_SIZE_MM, txt=license_type_line, ln=_NEXT_LINE) pdf.cell(0, _LINE_SIZE_MM, txt="License URL: %s" % entry.license_url, ln=_NEXT_LINE) pdf.ln() pdf.cell(0, _LINE_SIZE_MM, txt="License Text", ln=_NEXT_LINE) pdf.ln() pdf.set_font_size(_LICENSE_SIZE) if entry.license_encoded is not None: text = self._b64decode(entry.license_encoded) elif entry.license_url is not None: text = self._read_text_from_url(entry.license_url, entry) else: text = "ERROR: Could not read license text" try: pdf.multi_cell(0, _LINE_SIZE_MM, txt=text) except UnicodeEncodeError: logging.error(" could not encode license as PDF") pdf.cell(0, _LINE_SIZE_MM, txt="Could not read text of license", ln=_NEXT_LINE)
def printPdf(): pdf = FPDF() date = str(dt.datetime.now()) pdf.add_page(orientation='L') pdf.set_font("Arial", size=30) pdf.set_margins(left=10.0, top=20.0, right=10.0) pdf.cell(w=0, h=10, txt="EMI report", align="C") pdf.set_font_size(size=20) pdf.cell(w=0, h=10, txt=f"{dt.datetime.now()}", align="R", ln=1) pdf.cell(w=0, h=10, txt=f"Loan Amount :", align="L") pdf.cell(w=0, h=10, txt=f"{principal.get()}", align="R", ln=1) pdf.cell(w=0, h=10, txt=f"Rate of Interest :", align="L") pdf.cell(w=0, h=10, txt=f"{roi.get()}", align="R", ln=1) pdf.cell(w=0, h=10, txt=f"Time period of loan :", align="L") pdf.cell(w=0, h=10, txt=f"{noi.get()}", align="R", ln=1) pdf.cell(w=0, h=10, txt=f"Monthly EMI :", align="L") pdf.cell(w=0, h=10, txt=f"{emi.get()}", align="R", ln=1) pdf.cell(w=0, h=10, txt=f"Total Interest :", align="L") pdf.cell(w=0, h=10, txt=f"{total_interest.get()}", align="R", ln=1) pdf.cell(w=0, h=10, txt=f"payable amount :", align="L") pdf.cell(w=0, h=10, txt=f"{payable_amount.get()}", align="R", ln=1) pdf.output("emi-report-" + date[:10] + "-" + date[11:19].replace(":", "-") + ".pdf")
def _create_summary_page(self, pdf: FPDF, entries: List[LicenseReportEntry], unaccepted_packages: Set[str]): logging.debug(" generating summary page") pdf.add_page() pdf.set_font(_FONT) pdf.set_font_size(_TITLE_SIZE) pdf.cell(0, _LINE_SIZE_MM * 2, txt="License report", ln=_NEXT_LINE, align="C") pdf.ln() pdf.set_font_size(_NORMAL_SIZE) pdf.cell(0, _LINE_SIZE_MM, txt="Summary", ln=_NEXT_LINE) pdf.ln() summary = self.generate_summary(entries, unaccepted_packages) for key in sorted(summary): pdf.cell(_INDENT_MM, _LINE_SIZE_MM) pdf.cell(_LICENSE_COLUMN_WIDTH_MM, _LINE_SIZE_MM, txt=key) pdf.cell(0, _LINE_SIZE_MM, txt="%d" % summary[key]) pdf.ln()
def gen_pdf(): health_pdf = FPDF( ) # А4 с портретной ориентацией. Единица измерения: mm(миллиметр) deceased_pdf = FPDF() health_pdf.add_page() deceased_pdf.add_page() health_pdf.add_font('Segoe Print', '', 'fonts/segoepr.ttf', uni=True) # Segoe Print deceased_pdf.add_font('Segoe Print', '', 'fonts/segoepr.ttf', uni=True) health_pdf.add_font('Corbel', '', 'fonts/corbel.ttf', uni=True) deceased_pdf.add_font('Corbel', '', 'fonts/corbel.ttf', uni=True) health, deceased = put_names() health_pdf.set_font('Segoe Print') deceased_pdf.set_font('Segoe Print') health_pdf.set_font_size(30) deceased_pdf.set_font_size(30) health_pdf.set_text_color(76, 78, 75) deceased_pdf.set_text_color(76, 78, 75) health_pdf.image(name='images/крест.png', x=50, y=4, type='PNG') health_pdf.image(name='images/крест.png', x=143, y=4, type='PNG') deceased_pdf.image(name='images/крест.png', x=36, y=4, type='PNG') deceased_pdf.image(name='images/крест.png', x=157, y=4, type='PNG') health_pdf.cell(185, 5, txt='О ЗДРАВИИ', align='C', ln=1) deceased_pdf.cell(185, 5, txt='ОБ УПОКОЕНИИ', align='C', ln=1) health_pdf.set_xy(10, 20) deceased_pdf.set_xy(10, 20) health_pdf.set_font('Corbel') deceased_pdf.set_font('Corbel') health_pdf.set_font_size(18) deceased_pdf.set_font_size(18) health_pdf.set_text_color(0, 0, 0) deceased_pdf.set_text_color(0, 0, 0) health_pdf.write(h=8, txt=names(health)) deceased_pdf.write(h=8, txt=names(deceased)) health_pdf.output('output/health_notes.pdf') deceased_pdf.output('output/deceased_notes.pdf')
title_font_data['path'], uni=True) title_font = title_font_data['name'] # font for plain text if text_font_data['type'] == 'embeded': pdf.add_font(text_font_data['name'], '', os.path.abspath('.') + '/app/pdf/' + text_font_data['path'], uni=True) text_font = text_font_data['name'] # header section # left pdf.set_font(title_font, '', font_size['header_title']) pdf.cell(1, line_height['section'] + 1, data['header']['name'], ln=2) pdf.set_font_size(font_size['header_sub_title']) pdf.set_text_color(grey) pdf.cell(1, line_height['text'] + 1, data['header']['title'], ln=2) pdf.set_font_size(font_size['text'] + 2) online_text = data['pdf']['online']['text'] pdf.cell(pdf.get_string_width(online_text), line_height['text'] + 1, online_text, ln=0) pdf.set_text_color(*blue) pdf.cell(1, line_height['text'] + 1, data['pdf']['online']['url'], ln=2, link=data['pdf']['online']['url']) header_y = pdf.get_y()
class PdfHandler: def __init__(self, orientation='P', unit='pt', format='A4'): self.pdf_handler = FPDF(orientation=orientation, unit=unit, format=format) def _set_margins(self, left, top, right=-1): return self.pdf_handler.set_margins(left, top, right=right) def _set_title(self, title): return self.pdf_handler.set_title(title) def _set_subject(self, subject): return self.pdf_handler.set_subject(subject) def _set_author(self, author): return self.pdf_handler.set_author(author) def _set_keywords(self, keywords): return self.pdf_handler.set_keywords(keywords) def _set_creator(self, creator): return self.pdf_handler.set_creator(creator) def _add_page(self, orientation=''): return self.pdf_handler.add_page(orientation=orientation) def _set_draw_color(self, r, g=-1, b=-1): return self.pdf_handler.set_draw_color(r, g=g, b=b) def _set_fill_color(self, r, g=-1, b=-1): return self.pdf_handler.set_fill_color(g=g, b=b) def _set_text_color(self, r, g=-1, b=-1): return self.pdf_handler.set_text_color(r, g=-g, b=b) def _get_string_width(self, s): return self.pdf_handler.get_string_width(s) def _set_line_width(self, width): return self.pdf_handler.set_line_width(width) def _line(self, x1, y1, x2, y2): return self.pdf_handler.line(x1, y1, x2, y2) def _dashed_line(self, x1, y1, x2, y2, dash_length=1, space_length=1): return self.pdf_handler.dashed_line(x1, y1, x2, y2, dash_length=dash_length, space_length=space_length) def _rect(self, x, y, w, h, style=''): return self.pdf_handler.rect(x, y, w, h, style=style) def _ellipse(self, x, y, w, h, style=''): return self.pdf_handler.ellipse(x, y, w, h, style=style) def _set_font(self, family, style='', size=0): return self.pdf_handler.set_font(family, style=style, size=size) def _set_font_size(self, size): return self.pdf_handler.set_font_size(size) def _text(self, x, y, txt=''): return self.pdf_handler.text(x, y, txt=txt) def _multi_cell(self, w, h, txt='', border=0, align='J', fill=0, split_only=False): return self.pdf_handler.multi_cell(w, h, txt=txt, border=border, align=align, fill=fill, split_only=split_only) def _write(self, h, txt='', link=''): return self.pdf_handler.write(h, txt=txt, link=link) def _image(self, name, x=None, y=None, w=0, h=0, image_type='', link=''): return self.pdf_handler.image(name, x=x, y=y, w=w,h=h,type=image_type,link=link) def _normalize_text(self, txt): return self.pdf_handler.normalize_text(txt) def _output(self, name='', dest=''): return self.pdf_handler.output(name, dest)
class PDFPrinter: xCurrent = 0 yCurrent = 0 def __init__(self, path): self.path = path self.pdf = FPDF('P', 'mm', 'A4') self.page_setup() def page_setup(self): self.pdf.add_font("NotoSans", style="", fname="NotoSans-Regular.ttf", uni=True) self.pdf.add_font("NotoSans", style="B", fname="NotoSans-Bold.ttf", uni=True) self.pdf.add_font("NotoSans", style="I", fname="NotoSans-Italic.ttf", uni=True) self.pdf.add_font("NotoSans", style="BI", fname="NotoSans-BoldItalic.ttf", uni=True) self.pdf.set_font("NotoSans", size=8) self.pdf.add_page() def set_coordintates(self, x, y): self.xCurrent = x self.yCurrent = y def print_photo(self, img, name): x = self.xCurrent y = self.yCurrent self.pdf.image(img, x, y, PhotoSize.w, PhotoSize.h) # Write name below the image xText = x yText = y + PhotoSize.h + 2 # photo height + spacing self.pdf.set_font_size(6) self.pdf.text(xText, yText, name) def print_person_info(self, pi): self.pdf.set_font_size(8) x = self.xCurrent y = self.yCurrent self.pdf.text(x + TextDeltas.xName, y + TextDeltas.yName, pi.name) self.pdf.text(x + TextDeltas.xNationality, y + TextDeltas.yNationality, pi.nationality) self.pdf.text(x + TextDeltas.xFaculty, y + TextDeltas.yFaculty, pi.faculty) self.pdf.text(x + TextDeltas.xSection, y + TextDeltas.ySection, pi.section) self.pdf.text(x + TextDeltas.xBirthday, y + TextDeltas.yBirthday, pi.birthday.strftime("%d")) # day self.pdf.text(x + TextDeltas.xBirthday + CardSpacing.dayDelta, y + TextDeltas.yBirthday, pi.birthday.strftime("%m")) # month self.pdf.text(x + TextDeltas.xBirthday + CardSpacing.dayDelta + CardSpacing.dayDelta, y + TextDeltas.yBirthday, pi.birthday.strftime("%y")) # year self.pdf.text(x + TextDeltas.xValidity, y + TextDeltas.yValidity, pi.validity.strftime("%d")) # day self.pdf.text(x + TextDeltas.xValidity + CardSpacing.dayDelta, y + TextDeltas.yValidity, pi.validity.strftime("%m")) # month self.pdf.text(x + TextDeltas.xValidity + CardSpacing.dayDelta + CardSpacing.dayDelta, y + TextDeltas.yValidity, pi.validity.strftime("%y")) # year def output(self): self.pdf.output(self.path, "F") def add_page(self): self.pdf.add_page()
class Kut2FPDF(object): """ Convert kuts to pyFPDF. """ _document: "FPDF" _xml: Element _xml_data: Element _page_orientation: str _page_size: List[int] _bottom_margin: int _left_margin: int _right_margin: int _top_margin: int _page_top: Dict[int, int] _data_row: Element _parser_tools: "kparsertools.KParserTools" _avalible_fonts: List[str] _unavalible_fonts: List[str] design_mode: bool _actual_data_line: Optional[Element] _no_print_footer: bool _actual_section_size: int increase_section_size: int last_detail: bool actual_data_level: int last_data_processed: Element prev_level: int draws_at_header: Dict[str, str] detailn: Dict[str, int] name_: str _actual_append_page_no: int reset_page_count: bool def __init__(self) -> None: """Constructor.""" check_dependencies({"fpdf": "fpdf2"}) self._parser_tools = kparsertools.KParserTools() self._avalible_fonts = [] self._page_top: Dict[int, int] = {} self._unavalible_fonts = [] self.design_mode = config.value("ebcomportamiento/kugar_debug_mode", False) self._actual_data_line = None self._no_print_footer = False self.increase_section_size = 0 self.actual_data_level = 0 self.prev_level = -1 self.draws_at_header = {} self.detailn = {} self.name_ = "" self._actual_append_page_no = -1 self.reset_page_count = False self.new_page = False def parse(self, name: str, kut: str, data: str, report: "FPDF" = None, flags: List[int] = []) -> Optional[str]: """ Parse string containing ".kut" file into a pdf and return its file path. @param name. Filename path for ".kut". @param kut. String with ".kut" file contents. @param data. String with data to be used in the report. @return Path to PDF file. """ try: self._xml = self._parser_tools.loadKut(kut).getroot() except Exception: LOGGER.exception("KUT2FPDF: Problema al procesar %s.kut", name) return None try: self._xml_data = load2xml(data).getroot() except Exception: LOGGER.exception("KUT2FPDF: Problema al procesar xml_data") return None application.PROJECT.message_manager().send( "progress_dialog_manager", "create", ["Pineboo", len(self._xml_data), "kugar"]) application.PROJECT.message_manager().send( "progress_dialog_manager", "setLabelText", ["Creando informe ...", "kugar"]) self.name_ = name self.setPageFormat(self._xml) # self._page_orientation = # self._page_size = if report is None: from fpdf import FPDF # type: ignore self._actual_append_page_no = 0 self._document = FPDF(self._page_orientation, "pt", self._page_size) for font in self._document.core_fonts: LOGGER.debug("KUT2FPDF :: Adding font %s", font) self._avalible_fonts.append(font) else: self._document = report # Seteamos rutas a carpetas con tipos de letra ... if not hasattr(self._document, "set_stretching"): raise Exception("incorrect pyfpdf versión , you need <= 1.7.3") # Cargamos las fuentes disponibles next_page_break = (flags[2] == 1) if len(flags) == 3 else True page_append = (flags[1] == 1) if len(flags) > 1 else False page_display = (flags[0] == 1) if len(flags) > 0 else False if page_append: self.prev_level = -1 self.last_detail = False page_break = False if self.new_page: page_break = True self.new_page = False if self.reset_page_count: self.reset_page_no() self.reset_page_count = False if self.design_mode: print("Append", page_append) print("Display", page_display) print("Page break", next_page_break) if next_page_break: self.reset_page_count = True if page_display: self.new_page = True self.processDetails(not page_break) # FIXME:Alguno valores no se encuentran for pages in self._document.pages.keys(): page_content = self._document.pages[pages]["content"] for header in self.draws_at_header.keys(): page_content = page_content.replace( header, str(self.draws_at_header[header])) self._document.pages[pages]["content"] = page_content # print(self.draws_at_header.keys()) self._document.set_title(self.name_) self._document.set_author("Pineboo - kut2fpdf plugin") return self._document def get_file_name(self) -> Optional[str]: """Retrieve file name where PDF should be saved.""" import os pdf_name = application.PROJECT.tmpdir pdf_name += "/%s_%s.pdf" % ( self.name_, datetime.datetime.now().strftime("%Y%m%d%H%M%S")) if os.path.exists(pdf_name): os.remove(pdf_name) if self._document is not None: self._document.output(pdf_name, "F") return pdf_name else: return None def topSection(self) -> int: """ Retrieve top section margin for current page to calculate object positions. @return Number with ceiling for current page. """ return self._page_top[int(self._document.page_no())] def setTopSection(self, value: int) -> None: """ Update top section for current page. Usually updated when processing a section. @param value. Number specifying new ceiling. """ self._actual_section_size = value - self.topSection() self._page_top[int(self._document.page_no())] = value def newPage(self, data_level: int, add_on_header: bool = True) -> None: """ Add a new page to the document. """ self._document.add_page(self._page_orientation) self._page_top[int(self._document.page_no())] = self._top_margin self._document.set_margins( self._left_margin, self._top_margin, self._right_margin) # Lo dejo pero no se nota nada self._no_print_footer = False if self.design_mode: self.draw_margins() self._actual_section_size = 0 self._actual_append_page_no += 1 if self.design_mode: print("Nueva página", self.number_pages()) # l_ini = data_level # l_end = self.prev_level # if l_ini == l_end: # l_end = l_end + 1 # if l_ini <= l_end: # for l in range(l_ini , l_end): # print(l) # self.processSection("AddOnHeader", str(l)) pg_headers = self._xml.findall("PageHeader") for page_header in pg_headers: if self.number_pages() == 1 or page_header.get( "PrintFrequency") == "1": ph_level = (page_header.get("Level") if page_header.get("Level") is not None else None) self.processSection("PageHeader", int(ph_level or "0")) break if add_on_header and not self.number_pages() == 1: for level in range(data_level + 1): self.processSection("AddOnHeader", int(level)) # Por ahora se omite detail header def processDetails(self, keep_page: Optional[bool] = None) -> None: """ Process detail secions with their matching detailHeader and detailFooter. """ # Procesamos la cabecera si procede .. top_level = 0 level = 0 first_page_created = (keep_page if keep_page is not None and self._document.page_no() > 0 else False) rows_array = self._xml_data.findall("Row") i = 0 for data in rows_array: self._actual_data_line = data level_str: Optional[str] = data.get("level") if level_str is None: level_str = "0" level = int(level_str) if level > top_level: top_level = level if not first_page_created: self.newPage(level) first_page_created = True if rows_array[len(rows_array) - 1] is data: self.last_detail = True if level < self.prev_level: for lev in range(level + 1, self.prev_level + 1): self.processData("DetailFooter", self.last_data_processed, lev) if not str(level) in self.detailn.keys(): self.detailn[str(level)] = 0 else: self.detailn[str(level)] += 1 if level > self.prev_level: self.processData("DetailHeader", data, level) self.processData("Detail", data, level) self.last_data_processed = data self.prev_level = level application.PROJECT.message_manager().send( "progress_dialog_manager", "setProgress", [i, "kugar"]) i += 1 if not self._no_print_footer and hasattr(self, "last_data_processed"): for lev in reversed(range(top_level + 1)): self.processData("DetailFooter", self.last_data_processed, lev) application.PROJECT.message_manager().send("progress_dialog_manager", "destroy", ["kugar"]) def processData(self, section_name: str, data: Element, data_level: int) -> None: """ Check if detailHeader + detail + detailFooter do fit in the remaining page and create a new page if not. @param section_name. Section name to check @param data. Data to check @param data_level. Section level """ self.actual_data_level = data_level list_sections = self._xml.findall(section_name) # data_size = len(listDF) for section in list_sections: draw_if = section.get("DrawIf") show = True if draw_if: show = bool(data.get(draw_if)) if section.get("Level") == str(data_level) and show not in ( "", "False", "None"): if section_name in ("DetailHeader", "Detail"): height_calculated = ( self._parser_tools.getHeight(section) + self.topSection() + self.increase_section_size) if section_name == "DetailHeader": for detail in self._xml.findall("Detail"): if detail.get("Level") == str(data_level): height_calculated += self._parser_tools.getHeight( detail) for detail_footer in self._xml.findall("DetailFooter"): if detail_footer.get("Level") == str(data_level): height_calculated += self._parser_tools.getHeight( detail_footer) aof_size = 0 for add_footer in self._xml.findall("AddOnFooter"): # if add_footer.get("Level") == str(data_level): aof_size += self._parser_tools.getHeight(add_footer) height_calculated += self._parser_tools.getHeight( add_footer) page_footer: Any = self._xml.get("PageFooter") if isinstance(page_footer, Element): if (self._document.page_no() == 1 or page_footer.get("PrintFrecuency") == "1"): height_calculated += self._parser_tools.getHeight( page_footer) height_calculated += self._bottom_margin if (height_calculated + aof_size) > self._document.h: # Si nos pasamos self._no_print_footer = True # Vemos el tope por abajo limit_bottom = self._document.h - aof_size actual_size = self._parser_tools.getHeight( section) + self.topSection() if (actual_size >= limit_bottom - 2 ) or self.last_detail: # +2 se usa de margen extra self.processSection("AddOnFooter", int(data_level)) self.newPage(data_level) self.processXML(section, data) if section.get("NewPage") == "true" and not self.last_detail: self.newPage(data_level, False) break # Se ejecuta una sola instancia def processSection(self, name: str, level: int = 0) -> None: """ Process non-detail sections. @param name. Section name to process """ sec_list = self._xml.findall(name) sec_ = None for section in sec_list: if section.get("Level") == str( level) or section.get("Level") is None: sec_ = section break if sec_ is not None: if (sec_.get("PrintFrequency") == "1" or self._document.page_no() == 1 or name in ("AddOnHeader", "AddOnFooter")): self.processXML(sec_) def processXML(self, xml: Element, data: Optional[Element] = None) -> None: """ Process single XML element. @param xml: Element to process @param. data: Line affected """ fix_height = True if data is None: data = self._actual_data_line if self.design_mode and data is not None: print("Procesando", xml.tag, data.get("level")) size_updated = False if xml.tag == "DetailFooter": if xml.get("PlaceAtBottom") == "true": height = self._parser_tools.getHeight(xml) self.setTopSection(self._document.h - height - self.increase_section_size) size_updated = True if xml.tag == "PageFooter": fix_height = False if not size_updated: self.fix_extra_size( ) # Sirve para actualizar la altura con lineas que se han partido porque son muy largas for label in xml.iter("Label"): self.processText(label, data, fix_height) for field in xml.iter("Field"): self.processText(field, data, fix_height) for special in xml.iter("Special"): self.processText(special, data, fix_height, xml.tag) for calculated in xml.iter("CalculatedField"): self.processText(calculated, data, fix_height, xml.tag) # Busco draw_at_header en DetailFooter y los meto también if xml.tag == "DetailHeader": detail_level = xml.get("Level") if detail_level is None: raise Exception("Level tag not found") for detail_footer in self._xml.iter("DetailFooter"): if detail_footer.get("Level") == detail_level: for calculated_filed in detail_footer.iter( "CalculatedField"): if calculated_filed.get("DrawAtHeader") == "true": header_name = "%s_header_%s_%s" % ( self.detailn[detail_level], detail_level, calculated_filed.get("Field"), ) self.draws_at_header[header_name] = "" self.processText(calculated_filed, data, fix_height, xml.tag) for line in xml.iter("Line"): self.processLine(line, fix_height) if not size_updated: self.setTopSection(self.topSection() + self._parser_tools.getHeight(xml)) def fix_extra_size(self) -> None: """Increase size of the section if needed.""" if self.increase_section_size > 0: self.setTopSection(self.topSection() + self.increase_section_size) self.increase_section_size = 0 def processLine(self, xml: Element, fix_height: bool = True) -> None: """ Process single line. @param xml. Sección de xml a procesar. @param fix_height. Ajusta la altura a los .kut originales, excepto el pageFooter. """ color = xml.get("Color") red = 0 if not color else int(color.split(",")[0]) green = 0 if not color else int(color.split(",")[1]) blue = 0 if not color else int(color.split(",")[2]) style = int(xml.get("Style") or "0") width = int(xml.get("Width") or "0") pos_x1 = self.calculateLeftStart(xml.get("X1") or "0") pos_x1 = self.calculateWidth(pos_x1, 0, False) pos_x2 = self.calculateLeftStart(xml.get("X2") or "0") pos_x2 = self.calculateWidth(pos_x2, 0, False) # Ajustar altura a secciones ya creadas pos_y1 = int(xml.get("Y1") or "0") + self.topSection() pos_y2 = int(xml.get("Y2") or "0") + self.topSection() if fix_height: pos_y1 = self._parser_tools.ratio_correction_h(pos_y1) pos_y2 = self._parser_tools.ratio_correction_h(pos_y2) self._document.set_line_width( self._parser_tools.ratio_correction_h(width)) self._document.set_draw_color(red, green, blue) dash_length = 1 space_length = 1 if style == 2: dash_length = 20 space_length = 20 elif style == 3: dash_length = 10 space_length = 10 self._document.dashed_line(pos_x1, pos_y1, pos_x2, pos_y2, dash_length, space_length) # else: # self._document.line(X1, Y1, X2, Y2) def calculateLeftStart(self, position: Union[str, int, float]) -> int: """ Check if left margin is exceeded for current page. @param position. Position to check. @return Revised position. """ return self._parser_tools.ratio_correction_w( int(position)) + self._left_margin def calculateWidth(self, width: int, pos_x: int, fix_ratio: bool = True) -> int: """ Check if right margin is exceeded for current page. @param x. Position to check. @return Revised position. """ limit = self._document.w - self._right_margin ret_: int if fix_ratio: width = self._parser_tools.ratio_correction_w(width) pos_x = self._parser_tools.ratio_correction_w(pos_x) ret_ = width if pos_x + width > limit: ret_ = limit - pos_x else: ret_ = width return ret_ def processText( self, xml: Element, data_row: Optional[Element] = None, fix_height: bool = True, section_name: Optional[str] = None, ) -> None: """ Check tag (calculated, label, special or image). @param xml. XML section to process. @param fix_height. Revise height from original .kut file except pageFooter. """ is_image = False is_barcode = False text: str = xml.get("Text") or "" # borderColor = xml.get("BorderColor") field_name = xml.get("Field") or "" # x,y,W,H se calcula y corrigen aquí para luego estar correctos en los diferentes destinos posibles width = int(xml.get("Width") or "0") height = self._parser_tools.getHeight(xml) pos_x = int(xml.get("X") or "0") pos_y = (int(xml.get("Y") or "0") + self.topSection() ) # Añade la altura que hay ocupada por otras secciones if fix_height: pos_y = self._parser_tools.ratio_correction_h( pos_y) # Corrige la posición con respecto al kut original data_type = xml.get("DataType") if xml.tag == "Field" and data_row is not None: text = data_row.get(field_name) or "" elif xml.tag == "Special": if text == "": if xml.get("Type") == "1": text = "PageNo" text = self._parser_tools.getSpecial(text, self._actual_append_page_no) calculation_type = xml.get("CalculationType") if calculation_type is not None and xml.tag != "Field": if calculation_type == "6": function_name = xml.get("FunctionName") if function_name and data_row is not None: try: nodo = self._parser_tools.convertToNode(data_row) ret_ = application.PROJECT.call( function_name, [nodo, field_name], None, False) if ret_ is False: return else: text = str(ret_) except Exception: LOGGER.exception( "KUT2FPDF:: Error llamando a function %s", function_name) return else: return elif calculation_type == "1": text = self._parser_tools.calculate_sum( field_name, self.last_data_processed, self._xml_data, self.actual_data_level) elif calculation_type in ("5"): if data_row is None: data_row = self._xml_data[0] text = data_row.get(field_name) or "" if data_type is not None: text = self._parser_tools.calculated(text, int(data_type), xml.get("Precision"), data_row) if data_type == "5": is_image = True elif data_type == "6": is_barcode = True if xml.get("BlankZero") == "1" and text is not None: res_ = re.findall(r"\d+", text) if res_ == ["0"]: return if text is not None: from pineboolib.core.settings import config temporal = config.value("ebcomportamiento/temp_dir") if text.startswith(temporal): is_image = True # negValueColor = xml.get("NegValueColor") # Currency = xml.get("Currency") # # commaSeparator = xml.get("CommaSeparator") # dateFormat = xml.get("DateFormat") if is_image: self.draw_image(pos_x, pos_y, width, height, xml, text) elif is_barcode: self.draw_barcode(pos_x, pos_y, width, height, xml, text) elif data_row is not None: level = data_row.get("level") or "0" if level and str(level) in self.detailn.keys(): val = "%s_header_%s_%s" % (self.detailn[str(level)], level, field_name) if xml.get("DrawAtHeader") == "true" and level: if section_name == "DetailHeader": val = "" self.drawText(pos_x, pos_y, width, height, xml, val) # print(level, section_name, val, text) if section_name == "DetailFooter" and xml.get( "DrawAtHeader") == "true": self.draws_at_header[val] = text # print("Añadiendo a", val, text, level) else: self.drawText(pos_x, pos_y, width, height, xml, text) def drawText(self, pos_x: int, pos_y: int, width: int, height: int, xml: Element, txt: str) -> None: """ Draw a text field onto the page. @param pos_x. Label X Pos. @param pos_y. Label Y Pos. @param width. Label Width. @param height. Label Height. @param xml. Related XML Section @param txt. Computed text of the label to be created. """ if txt in ("None", None): # return txt = "" if width == 0 and height == 0: return txt = self._parser_tools.restore_text(txt) resizeable = False if xml.get("ChangeHeight") == "1": resizeable = True # height_resized = False orig_x = pos_x orig_y = pos_y orig_w = width orig_h = height # Corregimos margenes: pos_x = self.calculateLeftStart(pos_x) width = self.calculateWidth(width, pos_x) # bg_color = xml.get("BackgroundColor").split(",") fg_color = self.get_color(xml.get("ForegroundColor") or "") self._document.set_text_color(fg_color[0], fg_color[1], fg_color[2]) # self._document.set_draw_color(255, 255, 255) # if xml.get("BorderStyle") == "1": # FIXME: Hay que ajustar los margenes # font_name, font_size, font_style font_style = "" font_size = int(xml.get("FontSize") or "0") font_name_orig = ((xml.get("FontFamily") or "").lower() if xml.get("FontFamily") is not None else "helvetica") font_name = font_name_orig font_w = int(xml.get("FontWeight") or "50") if font_w == 50: # Normal font_w = 100 elif font_w >= 65: font_style += "B" font_w = 100 font_italic = xml.get("FontItalic") font_underlined = xml.get( "FontUnderlined") # FIXME: hay que ver si es así # background_color = self.get_color(xml.get("BackgroundColor")) # if background_color != [255,255,255]: #Los textos que llevan fondo no blanco van en negrita # font_style += "B" if font_italic == "1": font_style += "I" if font_underlined == "1": font_style += "U" font_name = font_name.replace(" narrow", "") font_full_name = "%s%s" % (font_name, font_style) if font_full_name not in self._avalible_fonts: font_found: Optional[str] = None if font_full_name not in self._unavalible_fonts: font_found = self._parser_tools.find_font( font_full_name, font_style) if font_found: if self.design_mode: LOGGER.warning( "KUT2FPDF::Añadiendo el tipo de letra %s %s (%s)", font_name, font_style, font_found, ) self._document.add_font(font_name, font_style, font_found, True) self._avalible_fonts.append(font_full_name) else: if font_full_name not in self._unavalible_fonts: if self.design_mode: LOGGER.warning( "KUT2FPDF:: No se encuentra el tipo de letra %s. Sustituido por helvetica%s." % (font_full_name, font_style)) self._unavalible_fonts.append(font_full_name) font_name = "helvetica" if font_name is not font_name_orig and font_name_orig.lower().find( "narrow") > -1: font_w = 85 self._document.set_font(font_name, font_style, font_size) self._document.set_stretching(font_w) # Corregir alineación vertical_alignment = xml.get( "VAlignment") # 0 izquierda, 1 centrado,2 derecha horizontal_alignment = xml.get("HAlignment") # layout_direction = xml.get("layoutDirection") start_section_size = self._actual_section_size result_section_size = 0 # Miramos si el texto sobrepasa el ancho array_text: List[str] = [] array_n = [] text_lines = [] if txt.find("\n") > -1: for line_text in txt.split("\n"): array_n.append(line_text) if array_n: # Hay saltos de lineas ... for n in array_n: text_lines.append(n) else: # No hay saltos de lineas text_lines.append(txt) for text_line in text_lines: if len(text_line) > 1: if text_line[0] == " " and text_line[1] != " ": text_line = text_line[1:] str_width = self._document.get_string_width(text_line) if ( str_width > width - 10 and xml.tag != "Label" and resizeable ): # Una linea es mas larga que el ancho del campo(Le quito 10 al ancho maximo para que corte parecido a kugar original) # height_resized = True array_text = self.split_text(text_line, width - 10) else: array_text.append(text_line) # calculated_h = orig_h * len(array_text) self.drawRect(orig_x, orig_y, orig_w, orig_h, xml) processed_lines = 0 extra_size = 0 for actual_text in array_text: processed_lines += 1 if processed_lines > 1: extra_size += font_size + 2 if horizontal_alignment == "1": # sobre X # Centrado pos_x = pos_x + (width / 2) - ( self._document.get_string_width(actual_text) / 2) # x = x + (width / 2) - (str_width if not height_resized else width / 2) elif horizontal_alignment == "2": # Derecha pos_x = (pos_x + width - self._document.get_string_width(actual_text) - 2 ) # -2 de margen # x = x + width - str_width if not height_resized else width else: # Izquierda if processed_lines == 1: pos_x = pos_x + 2 if vertical_alignment == "1": # sobre Y # Centrado # y = (y + ((H / 2) / processed_lines)) + (((self._document.font_size_pt / 2) / 2) * processed_lines) pos_y = int((orig_y + (orig_h / 2)) + ((self._document.font_size_pt / 2) / 2)) if len(array_text) > 1: pos_y = pos_y - (font_size // 2) elif vertical_alignment == "2": # Abajo pos_y = orig_y + orig_h - font_size else: # Arriba pos_y = orig_y + font_size pos_y = pos_y + extra_size if self.design_mode: self.write_debug( self.calculateLeftStart(orig_x), pos_y, "Hal:%s, Val:%s, T:%s st:%s" % (horizontal_alignment, vertical_alignment, txt, font_w), 6, "green", ) if xml.tag == "CalculatedField": self.write_debug( self.calculateLeftStart(orig_x), pos_y, "CalculatedField:%s, Field:%s" % (xml.get("FunctionName"), xml.get("Field")), 3, "blue", ) self._document.text(pos_x, pos_y, actual_text) result_section_size += start_section_size result_section_size = result_section_size - start_section_size if (self.increase_section_size < extra_size ): # Si algun incremento extra hay superior se respeta self.increase_section_size = extra_size def split_text(self, texto: str, limit_w: int) -> List[str]: """Split text into lines based on visual width.""" list_ = [] linea_: Optional[str] = None for parte in texto.split(" "): if linea_ is None and parte == "": continue if linea_ is not None: if self._document.get_string_width(linea_ + parte) > limit_w: list_.append(linea_) linea_ = "" else: linea_ = "" linea_ += "%s " % parte if linea_ is not None: list_.append(linea_) return list_ def get_color(self, value: str) -> List[int]: """Convert color text into [r,g,b] array.""" lvalue = value.split(",") red: int green: int blue: int if len(lvalue) == 3: red = int(lvalue[0]) green = int(lvalue[1]) blue = int(lvalue[2]) else: red = int(value[0:2]) green = int(value[3:5]) blue = int(value[6:8]) return [red, green, blue] def drawRect(self, pos_x: int, pos_y: int, width: int, height: int, xml: Element = None) -> None: """ Draw a rectangle in current page. @param pos_x. left side @param pos_y. top side @param width. width @param height. heigth """ style_ = "" border_color = None bg_color = None line_width = self._document.line_width border_width = 0.2 # Calculamos borde y restamos del ancho orig_x = pos_x orig_y = pos_y orig_w = width pos_x = self.calculateLeftStart(orig_x) width = self.calculateWidth(width, pos_x) if xml is not None and not self.design_mode: if xml.get("BorderStyle") == "1": border_color = self.get_color(xml.get("BorderColor") or "") self._document.set_draw_color(border_color[0], border_color[1], border_color[2]) style_ += "D" bg_color = self.get_color(xml.get("BackgroundColor") or "") self._document.set_fill_color(bg_color[0], bg_color[1], bg_color[2]) style_ = "F" + style_ border_width = int( xml.get("BorderWidth") or "0" if xml.get("BorderWidth" ) else 0.2) else: self.write_cords_debug(pos_x, pos_y, width, height, orig_x, orig_w) style_ = "D" self._document.set_draw_color(0, 0, 0) if style_ != "": self._document.set_line_width(border_width) self._document.rect(pos_x, pos_y, width, height, style_) self._document.set_line_width(line_width) self._document.set_xy(orig_x, orig_y) # self._document.set_draw_color(255, 255, 255) # self._document.set_fill_color(0, 0, 0) def write_cords_debug( self, pos_x: Union[float, int], pos_y: Union[float, int], width: Union[float, int], height: Union[float, int], orig_x: Union[float, int], orig_w: Union[float, int], ) -> None: """Debug for Kut coordinated.""" self.write_debug( int(pos_x), int(pos_y), "X:%s Y:%s W:%s H:%s orig_x:%s, orig_W:%s" % ( round(pos_x, 2), round(pos_y, 2), round(width, 2), round(height, 2), round(orig_x, 2), round(orig_w, 2), ), 2, "red", ) def write_debug(self, pos_x: int, pos_y: int, text: str, height: int, color: Optional[str] = None) -> None: """Write debug data into the report.""" orig_color = self._document.text_color red = 0 green = 0 blue = 0 current_font_family = self._document.font_family current_font_size = self._document.font_size_pt current_font_style = self._document.font_style if color == "red": red = 255 elif color == "green": green = 255 elif color == "blue": blue = 255 self._document.set_text_color(red, green, blue) self._document.set_font_size(4) self._document.text(pos_x, pos_y + height, text) self._document.text_color = orig_color # self._document.set_xy(orig_x, orig_y) self._document.set_font(current_font_family, current_font_style, current_font_size) def draw_image(self, pos_x: int, pos_y: int, width: int, height: int, xml: Element, file_name: str) -> None: """ Draw image onto current page. @param pos_x. left position @param pos_y. top position @param width. width @param height. heigth @param xml. Related XML section @param file_name. filename of temp data to use """ import os if not file_name.lower().endswith(".png"): file_name_ = self._parser_tools.parseKey(file_name) if file_name_ is None: return file_name = file_name_ if os.path.exists(file_name): pos_x = self.calculateLeftStart(pos_x) width = self.calculateWidth(width, pos_x) self._document.image(file_name, pos_x, pos_y, width, height, "PNG") def draw_barcode(self, pos_x: int, pos_y: int, width: int, height: int, xml: Element, text: str) -> None: """ Draw barcode onto currrent page. """ if text == "None": return from pineboolib.fllegacy import flcodbar file_name = application.PROJECT.tmpdir file_name += "/%s.png" % (text) codbartype = xml.get("CodBarType") if not os.path.exists(file_name): bar_code = flcodbar.FLCodBar(text) # Code128 if codbartype is not None: type: int = bar_code.nameToType(codbartype.lower()) bar_code.setType(type) bar_code.setText(text) pix = bar_code.pixmap() if not pix.isNull(): pix.save(file_name, "PNG") self.draw_image(pos_x + 10, pos_y, width - 20, height, xml, file_name) def setPageFormat(self, xml: Element) -> None: """ Define page parameters. @param xml: XML with KUT data """ custom_size = None self._bottom_margin = int(xml.get("BottomMargin") or "0") self._left_margin = int(xml.get("LeftMargin") or "0") self._right_margin = int(xml.get("RightMargin") or "0") self._top_margin = int(xml.get("TopMargin") or "0") page_size = int(xml.get("PageSize") or "0") page_orientation = xml.get("PageOrientation") or "0" if page_size in [30, 31]: custom_size = [ int(xml.get("CustomHeightMM") or "0"), int(xml.get("CustomWidthMM") or "0"), ] self._page_orientation = "P" if page_orientation == "0" else "L" self._page_size = self._parser_tools.convertPageSize( page_size, int(page_orientation), custom_size) # devuelve un array def draw_margins(self) -> None: """Draw margins on the report.""" self.draw_debug_line(0 + self._left_margin, 0, 0 + self._left_margin, self._page_size[1]) # Vertical derecha self.draw_debug_line( self._page_size[0] - self._right_margin, 0, self._page_size[0] - self._right_margin, self._page_size[1], ) # Vertical izquierda self.draw_debug_line(0, 0 + self._top_margin, self._page_size[0], 0 + self._top_margin) # Horizontal superior self.draw_debug_line( 0, self._page_size[1] - self._bottom_margin, self._page_size[0], self._page_size[1] - self._bottom_margin, ) # Horizontal inferior def draw_debug_line( self, pos_x1: int, pos_y1: int, pos_x2: int, pos_y2: int, title: Optional[str] = None, color: str = "GREY", ) -> None: """Draw a debug line on the report.""" dash_length = 2 space_length = 2 red = 0 green = 0 blue = 0 if color == "GREY": red = 220 green = 220 blue = 220 self._document.set_line_width(1) self._document.set_draw_color(red, green, blue) self._document.dashed_line(pos_x1, pos_y1, pos_x2, pos_y1, dash_length, space_length) def number_pages(self) -> int: """Get number of pages on the report.""" return self._actual_append_page_no if self._actual_append_page_no > 0 else 0 def reset_page_no(self) -> None: """Reset page number.""" self._actual_append_page_no = -1
class PDF: datum = datetime.today().strftime('%d.%m.%Y') datum2 = (datetime.today() + timedelta(days=30)).strftime('%d.%m.%Y') kundennummer = str(randint(1000000000, 9999999999)) kontonummer = str(randint(100000000000000, 999999999999999)) iban = 'DE' + str(kontonummer) rechnungsnummer = str(randint(1000000000, 9999999999)) db = None pdf = None def __init__(self, db, shoppingbag, dir, vorname, nachname, email, telefon, strasse, plz, ort, list_products, shoppingbag_instance): self.db = db if len(str(vorname.get())) == 0 or str(vorname.get()).isspace() or len( str(nachname.get())) == 0 or str( nachname.get()).isspace() or len(str(email.get( ))) == 0 or str(email.get()).isspace() or len( str(telefon.get())) == 0 or str( telefon.get()).isspace() or len(str( strasse.get())) == 0 or str( strasse.get()).isspace() or len( str(plz.get())) == 0 or str( plz.get()).isspace() or len( str(ort.get())) == 0 or str( ort.get()).isspace(): error = Tk() error.title("Fehler") error.resizable(0, 0) frame = Frame(error, width=240, height=20, bg='white') var_error = StringVar(master=error, value='Kontoinformationen unvollständig!') error_output = Entry(frame, width=30, font=("Calibri", 12), fg='red', textvariable=var_error, borderwidth=0) error_output.place(x=0, y=0) frame.pack() error.mainloop() # PDF initialisieren self.pdf = FPDF(orientation='P', unit='mm', format='A4') self.pdf.add_page() self.pdf.image("rechnung_background.gif", x=0, y=0, w=210) # Rechnung self.pdf.set_xy(100, 66) self.pdf.set_font("Times", style='B', size=48) self.pdf.set_text_color(255, 173, 22) self.pdf.cell(93, 13, txt="RECHNUNG", ln=1, align="R") # Name name = str(vorname.get()) + " " + str(nachname.get()) self.pdf.set_xy(6, 30) self.pdf.set_font("Times", style='', size=12) self.pdf.set_text_color(0, 0, 0) self.pdf.cell(100, 4, txt=name, ln=1, align="L") # Straße self.pdf.set_xy(6, 37) self.pdf.cell(100, 4, txt=str(strasse.get()), ln=1, align="L") # PLZ und Ort plz_ort = str(plz.get()) + " " + str(ort.get()) self.pdf.set_xy(6, 44) self.pdf.cell(100, 4, txt=plz_ort, ln=1, align="L") # E-Mail-Adresse self.pdf.set_xy(6, 63) self.pdf.set_font_size(9) self.pdf.set_text_color(255, 173, 22) self.pdf.cell(100, 4, txt="E-Mail", ln=1, align="L") self.pdf.set_xy(18, 63) self.pdf.set_text_color(0, 0, 0) self.pdf.cell(100, 4, txt=str(email.get()), ln=1, align="L") # Telefonnummer self.pdf.set_xy(6, 69) self.pdf.set_text_color(255, 173, 22) self.pdf.cell(100, 4, txt="Tel", ln=1, align="L") self.pdf.set_xy(14, 69) self.pdf.set_text_color(0, 0, 0) self.pdf.cell(100, 4, txt=str(telefon.get()), ln=1, align="L") # Datum self.pdf.set_xy(6, 75) self.pdf.set_text_color(255, 173, 22) self.pdf.cell(100, 4, txt="Datum", ln=1, align="L") self.pdf.set_xy(18, 75) self.pdf.set_text_color(0, 0, 0) self.pdf.cell(100, 4, txt=str(self.datum), ln=1, align="L") # Kundennummer self.pdf.set_xy(6, 81) self.pdf.set_text_color(255, 173, 22) self.pdf.cell(100, 4, txt="Kundennummer", ln=1, align="L") self.pdf.set_xy(30, 81) self.pdf.set_text_color(0, 0, 0) self.pdf.cell(100, 4, txt=self.kundennummer, ln=1, align="L") # Rechnungsnummer self.pdf.set_xy(6, 87) self.pdf.set_text_color(255, 173, 22) self.pdf.cell(100, 4, txt="Rechnungsnummer", ln=1, align="L") self.pdf.set_xy(35, 87) self.pdf.set_text_color(0, 0, 0) self.pdf.cell(100, 4, txt=self.rechnungsnummer, ln=1, align="L") # ------------------------------------------------------- # Einleitung self.pdf.set_xy(13, 120) self.pdf.set_font("Times", style='', size=12) self.pdf.set_text_color(0, 0, 0) self.pdf.cell( 100, 4, txt="Hiermit stellen wir Ihnen folgende Positionen in Rechnung.", ln=1, align="L") # ------------------------------------------------------- # Tabelle Kopfzeile self.pdf.set_xy(20, 140) self.pdf.set_font("Times", style='b', size=10) self.pdf.set_text_color(255, 255, 255) self.pdf.cell(100, 4, txt="Artikelnummer", ln=1, align="L") self.pdf.set_xy(62, 140) self.pdf.cell(100, 4, txt="Name", ln=1, align="L") self.pdf.set_xy(110, 140) self.pdf.cell(100, 4, txt="Einzelpreis", ln=1, align="L") self.pdf.set_xy(145, 140) self.pdf.cell(100, 4, txt="Menge", ln=1, align="L") self.pdf.set_xy(175, 140) self.pdf.cell(100, 4, txt="Betrag", ln=1, align="L") # ------------------------------------------------------- # Produkte self.pdf.set_font("Times", style='', size=10) self.pdf.set_text_color(0, 0, 0) query = {'in_shoppingbag': {'$gt': 0}} doc = db.col.find(query) y = 149 for entry in doc: self.addEntry( y, str(entry['artikelnummer']), str(entry['name']), str( float(entry['preis']) - float(entry['rabatt']) + float(entry['pfand'])), str(entry['in_shoppingbag']), str( float( float(entry['preis']) - float(entry['rabatt']) + float(entry['pfand'])) * int(entry['in_shoppingbag']))) self.pdf.image("separator.gif", x=0, y=y + 6, w=210) y += 9 if y == 257 or y == 365 or y == 473: self.pdf.add_page() y = 32 # ------------------------------------------------------- # Mehrwertsteuer und Rechnungsbetrag errechnen summe = 0.0 query = {'in_shoppingbag': {'$gt': 0}} doc = db.col.find(query) for entry in doc: summe += float( (float(entry['preis']) - float(entry['rabatt']) + float(entry['pfand'])) * int(entry['in_shoppingbag'])) mwst = 0.19 * summe rechnungsbetrag = StringVar(value=str("%.2f" % float(summe))) mwst = StringVar(value=str("%.2f" % float(mwst))) # Mehrwertsteuer self.pdf.set_xy(145, y) self.pdf.cell(100, 4, txt="davon MwSt.", ln=1, align="L") self.pdf.set_xy(175, y) self.pdf.cell(100, 4, txt=str(mwst.get()) + " " + chr(128), ln=1, align="L") y += 9 # Rechnungsbetrag self.pdf.image("rechnungsbetrag_background.gif", x=140, y=y - 2, w=70) self.pdf.set_font("Times", style='b', size=10) self.pdf.set_text_color(255, 255, 255) self.pdf.set_xy(145, y) self.pdf.cell(100, 4, txt="Rechnungsbetrag", ln=1, align="L") self.pdf.set_xy(175, y) self.pdf.cell(100, 4, txt=str(rechnungsbetrag.get()) + " " + chr(128), ln=1, align="L") # ------------------------------------------------------- # Schluss self.pdf.set_font("Times", style='', size=12) self.pdf.set_text_color(0, 0, 0) self.pdf.set_xy(13, y + 30) self.pdf.cell(100, 4, txt="Bitte überweisen Sie den Rechnungsbetrag bis zum " + str(self.datum2) + " auf unser Konto mit der ", ln=1, align="L") self.pdf.set_xy(13, y + 38) self.pdf.cell(100, 4, txt="IBAN '" + str(self.iban) + "' und dem Verwendungszweck '" + str(self.rechnungsnummer) + "'.", ln=1, align="L") # ------------------------------------------------------- dir = str(dir).replace("/", "\\") if len(dir) > 0: # auf_lager reduzieren query = {'in_shoppingbag': {'$gt': 0}} doc = db.col.find(query) for entry in doc: entry_query = {'artikelnummer': int(entry['artikelnummer'])} new = int(entry['auf_lager']) - int(entry['in_shoppingbag']) newvalue = {'$set': {'auf_lager': int(new)}} db.col.update_one(entry_query, newvalue) # Anzeigen und Einträge aktualisieren for prod in list_products: query = {'artikelnummer': prod.entry['artikelnummer']} doc = db.col.find(query) for entry in doc: prod.setentry(entry) if prod.info: prod.var_auflager.set(int(prod.entry['auf_lager'])) prod.var_inshoppingbag.set(0) newvalue = {'$set': {'in_shoppingbag': 0}} db.col.update_one(query, newvalue) img_shoppingbag_empty = PhotoImage( file='shoppingbag_empty_small.gif') prod.product_shoppingbag.config(image=img_shoppingbag_empty) prod.product_shoppingbag.photo = img_shoppingbag_empty shoppingbag_instance.update() # Fenster schließen und Rechnungs-PDF erstellen shoppingbag.destroy() self.pdf.output(str(dir) + "\\Rechnung.pdf") # ------------------------------------------------------- # Erfolg Fenster success = Tk() success.title("Erfolg") success.resizable(0, 0) frame = Frame(success, width=240, height=20, bg='white') var_success = StringVar(master=success, value='Rechnung erfolgreich erstellt!') success_output = Entry(frame, width=30, font=("Calibri", 12), fg='green', textvariable=var_success, borderwidth=0) success_output.place(x=0, y=0) frame.pack() success.mainloop() # Eintrag zur Rechnungsübersicht mit Positionen und Inhalten hinzufügen def addEntry(self, y, artikelnummer, name, einzelpreis, menge, betrag): self.pdf.set_xy(20, y) self.pdf.cell(100, 4, txt=artikelnummer, ln=1, align="L") # Name self.pdf.set_xy(62, y) self.pdf.cell(100, 4, txt=name, ln=1, align="L") # Einzelpreis self.pdf.set_xy(110, y) self.pdf.cell(100, 4, txt=str("%.2f" % float(einzelpreis)) + " " + chr(128), ln=1, align="L") # Menge self.pdf.set_xy(145, y) self.pdf.cell(100, 4, txt=menge, ln=1, align="L") # Menge self.pdf.set_xy(175, y) self.pdf.cell(100, 4, txt=str("%.2f" % float(betrag)) + " " + chr(128), ln=1, align="L")
class InterpretablePDF: """ Class to produce formatted vignettes that indicate which text elements are contributing to any given classification. Currently this class only works with the CAP Prostate Cancer data, because the formatting corresponds to the unique structure of this text data. However, it could easily be adapted to work with other textual data (such as LeDeR). """ def __init__(self, classifier, x_data, y_data, feature_columns, base_font_size=12, line_height=8, header_col_width=100, legend_offset=47.5, legend_offset_2=63, top_n_features=None, contributions=None): self.font_size = base_font_size self.line_height = line_height self.header_col_width = header_col_width self.legend_offset = legend_offset self.legend_offset_2 = legend_offset_2 self.top_n = top_n_features self.pdf = None self.original_data = None self.feature_columns = feature_columns self.X = x_data self.y = y_data self.clf = classifier _, _, self.contributions = (run_tree_interpreter(self.clf, self.X) if contributions is None else (None, None, contributions)) self.stemmer = WordNetLemmatizer() self.section_headers = [ 'Clinical features at diagnosis', 'Treatments received', 'Prostate cancer progression', 'Progression of co-morbidities', 'End of life' ] self.vignette_column_names = [ 'Gleason Score at diagnosis (with dates)', 'Clinical stage (TNM)', 'Pathological stage (TNM)', 'Co-morbidities with dates of diagnosis', 'Other primary cancers with dates of diagnosis', 'PSA level at diagnosis with dates', 'Radiological evidence of local spread at diagnosis', 'Radiological evidence of metastases at diagnosis', 'Initial treatments (dates)', 'Hormone therapy (start date)', 'Maximum androgen blockade (start date)', 'Orchidectomy (date)', 'Chemotherapy (start date)', 'Treatment for complications of treating prostate cancer with dates (if available)', 'Serial PSA levels (dates)', 'Serum testosterone', 'Radiological evidence of metastases', 'Other indications or complications of disease progression', 'Date of recurrence following radical surgery or radiotherapy', 'Palliative care referrals and treatments', 'Treatment/ admission for co-morbidity with dates (if available)', 'Symptoms in last 3-6 months (i.e. bone pain, weight loss, cachexia,\ loss of appetite, obstructive uraemia)', 'Last consultation: speciality & date', 'Was a DS1500 report issued?', 'Post mortem findings' ] def create_pdf(self, case_id, original_data, filename): self.original_data = original_data self.pdf = FPDF() self.pdf.add_page() self.pdf.set_font('Arial', 'B', self.font_size) self.pdf.cell( w=0, h=self.line_height, txt= 'Interpretable Vignette Classification for Cause of Death Review', border=0, ln=0, align='C', fill=False, link='') self.pdf.set_font('') self.pdf.ln() self.pdf.ln() y = self.pdf.get_y() self.pdf.multi_cell( w=self.header_col_width, h=self.line_height, txt= 'Study ID number : %s\nDate of death : %s\nDate of diagnosis : %s' % (original_data['cp1random_id_5_char'], original_data['cnr19datedeath'].date(), original_data['cnr_date_pca_diag'].date()), border=0, align='L', fill=False) self.pdf.y = y self.pdf.x = self.header_col_width self.pdf.multi_cell( w=self.header_col_width, h=self.line_height, txt= 'Predicted death code: %d (%.2f)\nActual death code: %d\nCOD route: %d' % (self.clf.best_estimator_.predict(self.X)[case_id], self.clf.best_estimator_.predict_proba(self.X)[case_id][1], original_data.pca_death_code, original_data.cp1do_cod_route), border=0, align='R', fill=False) self.pdf.set_line_width(0.5) self.pdf.line(10, self.pdf.get_y(), 210 - 10, self.pdf.get_y()) self.pdf.set_line_width(0.2) self.write_legend(case_id) for ci, col in enumerate(self.feature_columns): self.pdf.set_text_color(0, 0, 0) self.pdf.set_font_size(self.font_size) if ci in [0, 8, 14, 20, 21]: self.print_section_header(0) self.pdf.line(10, self.pdf.get_y(), 210 - 10, self.pdf.get_y()) self.pdf.write(self.line_height, self.vignette_column_names[ci] + ': ') if 'palliative' not in col: text = str(original_data[col]) self.print_paragraph(text, case_id) self.pdf.output(filename) def get_font_size_and_color(self, contribution, min_contribution, max_contribution, shrink=0.5): c = (255, 160, 0) if contribution < 0 else (0, 0, 255) s = ((self.font_size * shrink) + 1.5 * self.font_size * (np.absolute(contribution) - min_contribution) / float(max_contribution - min_contribution)) return s, c def legend_entry(self, fimps, fimp, align): size, color = self.get_font_size_and_color(fimp.contribution, fimps.magnitude.min(), fimps.magnitude.max()) self.pdf.set_text_color(*color) self.pdf.set_font_size(size) self.pdf.cell(w=self.legend_offset, h=self.line_height, txt=fimp.feature, border=0, ln=0, align=align, fill=False, link='') def legend_label(self, text, align): self.pdf.cell(w=self.legend_offset_2, h=self.line_height, txt=text, border=0, ln=0, align=align, fill=False, link='') def write_legend(self, case_id): self.pdf.cell(w=0, h=self.line_height, txt='Feature contribution legend', border=0, ln=0, align='C', fill=False, link='') self.pdf.ln() fimps = get_ti_feature_contributions_for_instance_i( case_id, self.contributions, self.clf).sort_values(by='magnitude', ascending=False) fimps = fimps.head(self.top_n) if self.top_n is not None else fimps fimp = fimps.loc[fimps.contribution.idxmin()] self.legend_entry(fimps, fimp, align='L') fimp = fimps.loc[fimps.contribution < 0] fimp = fimp.loc[fimp.contribution.idxmax()] self.legend_entry(fimps, fimp, align='R') fimp = fimps.loc[fimps.contribution > 0] fimp = fimp.loc[fimp.contribution.idxmin()] self.legend_entry(fimps, fimp, align='L') fimp = fimps.loc[fimps.contribution.idxmax()] self.legend_entry(fimps, fimp, align='R') self.pdf.ln() self.pdf.set_text_color(0, 0, 0) self.pdf.set_font('Arial', '', self.font_size * .6) self.legend_label('Largest negative contribution', 'L') self.legend_label('Smallest contributions', 'C') self.legend_label('Largest positive contribution', 'R') self.pdf.set_font('Arial', '', self.font_size) def print_section_header(self, section): self.pdf.ln() self.pdf.set_line_width(0.5) self.pdf.line(10, self.pdf.get_y(), 210 - 10, self.pdf.get_y()) self.pdf.set_line_width(0.2) self.pdf.set_font('Arial', 'B', self.font_size) self.pdf.write(self.line_height, self.section_headers[section] + '\n') self.pdf.set_font('') # REFACTOR! def print_paragraph(self, text, i, base_color=(128, 128, 128)): fimps = get_ti_feature_contributions_for_instance_i( i, self.contributions, self.clf) fimps.sort_values(by='magnitude', inplace=True, ascending=False) fimps = fimps.head(self.top_n) old_word = '' old_tr_word = '' old_bigram = '' old_bigram_contribution = None old_color = base_color old_size = self.font_size words = text.split(' ') words.append(' .') for word in words: tr_word = self.transform_text(word) feat_tr = old_tr_word + ' ' + tr_word contribution_bi = ( fimps.loc[fimps.feature == feat_tr].iloc[0].contribution if feat_tr in list(fimps.feature) else None) magnitude_bi = np.absolute( contribution_bi) if contribution_bi is not None else 0 feat_tr = old_tr_word contribution_uni = ( fimps.loc[fimps.feature == feat_tr].iloc[0].contribution if feat_tr in list(fimps.feature) else None) magnitude_uni = np.absolute( contribution_uni) if contribution_uni is not None else 0 if contribution_bi and magnitude_bi > magnitude_uni: # print('bigram: ', old_tr_word) feat_tr = old_tr_word + ' ' + tr_word feat = old_word + ' ' + word contribution = fimps.loc[fimps.feature == feat_tr].iloc[0].contribution size, color = self.get_font_size_and_color( contribution, fimps.magnitude.min(), fimps.magnitude.max()) self.pdf.set_text_color(*color) self.pdf.set_font_size(size) feat = feat.encode('latin-1', 'replace').decode('latin-1') self.pdf.write(self.line_height, feat + ' ') old_word = '' old_tr_word = '' old_color = base_color old_size = self.font_size elif contribution_uni and magnitude_uni > magnitude_bi: # print('unigram: ', old_tr_word) feat_tr = old_tr_word feat = old_word contribution = fimps.loc[fimps.feature == feat_tr].iloc[0].contribution size, color = self.get_font_size_and_color( contribution, fimps.magnitude.min(), fimps.magnitude.max()) self.pdf.set_text_color(*color) self.pdf.set_font_size(size) feat = feat.encode('latin-1', 'replace').decode('latin-1') self.pdf.write(self.line_height, feat + ' ') old_word = word old_tr_word = tr_word old_color = base_color old_size = self.font_size else: self.pdf.set_text_color(*old_color) self.pdf.set_font_size(old_size) w = old_word.encode('latin-1', 'replace').decode('latin-1') self.pdf.write(self.line_height, w + ' ') old_word = word old_tr_word = tr_word old_color = base_color old_size = self.font_size self.pdf.ln() def transform_text(self, text): # Remove all the special characters document = re.sub(r'\W', ' ', str(text)) # remove all single characters document = re.sub(r'\s+[a-zA-Z]\s+', ' ', document) # document = re.sub(r'\s+[a-zA-Z]\s+', ' ', str(X[sen])) # Remove single characters from the start document = re.sub(r'\^[a-zA-Z]\s+', ' ', document) # Substituting multiple spaces with single space document = re.sub(r'\s+', ' ', document, flags=re.I) # Removing prefixed 'b' document = re.sub(r'^b\s+', '', document) # Converting to Lowercase document = document.lower() # Lemmatization document = document.split() document = [self.stemmer.lemmatize(word) for word in document] document = ' '.join(document) return document
def create_pdf(faste_medisiner, behovsmedisiner): pdf = FPDF('P', 'mm', 'A4') pdf.add_font('DejaVu', '', 'DejaVuSans.ttf', uni=True) pdf.set_font('DejaVu', '', LARGE_FONT_SIZE) while faste_medisiner or behovsmedisiner: pdf.add_page() pos_y = 106.5 # Start faste medisiner pdf.set_xy(11, pos_y) i = 1 while faste_medisiner and i <= 15: medisin = faste_medisiner.pop(0) medisin = medisin.strip() medisin = '→ ' + medisin if len(medisin) > 30: pdf.set_font_size(SMALL_FONT_SIZE) # go small if len(medisin) > 40: # go multi line! medisin = textwrap.fill(medisin, 40) medisin_lines = medisin.splitlines() pos_y -= 2 pdf.set_xy(11, pos_y) pdf.cell(10, 10, medisin_lines[0], 0) pos_y += 3 pdf.set_xy(11, pos_y) pdf.cell(10, 10, medisin_lines[1], 0) pos_y = pos_y + 7.9 else: # go single line pdf.cell(10, 10, medisin, 0) pos_y = pos_y + 8.9 pdf.set_font_size(LARGE_FONT_SIZE) else: pdf.cell(40, 10, medisin, 0) pos_y = pos_y + 8.9 pdf.set_xy(11, pos_y) i += 1 pdf.add_page() pdf.set_auto_page_break(False) # Behovsmedisiner pdf.set_font_size(SMALL_FONT_SIZE) pos_y = 233 pdf.set_xy(4, pos_y) i = 1 while behovsmedisiner and i <= 10: medisin = behovsmedisiner.pop(0) medisin = medisin.strip() medisin = '→ ' + medisin pdf.cell(40, 10, medisin, 0) pos_y = pos_y + 5.5 pdf.set_xy(4, pos_y) i += 1 return pdf.output(name='kurve', dest='S').encode('latin-1')
class Report: def __init__(self, data: DataSet, stats=None) -> None: self.output_path = os.path.join(data.data_path, "stats") self.dataset_name = os.path.basename(data.data_path) self.io_handler = data.io_handler self.mapi_light_light_green = [255, 255, 255] self.mapi_light_green = [0, 0, 0] self.mapi_light_grey = [218, 222, 228] self.mapi_dark_grey = [0, 0, 0] self.pdf = FPDF("P", "mm", "A4") self.pdf.add_page() self.title_size = 20 self.h1 = 16 self.h2 = 13 self.h3 = 10 self.text = 10 self.small_text = 8 self.margin = 10 self.cell_height = 7 self.total_size = 190 self.odm_stat = 'odm_processing_statistics' if stats is not None: self.stats = stats else: self.stats = self._read_stats_file("stats.json") def save_report(self, filename: str) -> None: # pyre-fixme[28]: Unexpected keyword argument `dest`. bytestring = self.pdf.output(dest="S") if isinstance(bytestring, str): bytestring = bytestring.encode("utf8") with self.io_handler.open(os.path.join(self.output_path, filename), "wb") as fwb: fwb.write(bytestring) def _make_table(self, columns_names, rows, row_header=False) -> None: self.pdf.set_font("Helvetica", "", self.h3) self.pdf.set_line_width(0.3) columns_sizes = [int(self.total_size / len(rows[0]))] * len(rows[0]) if columns_names: self.pdf.set_draw_color(*self.mapi_light_grey) self.pdf.set_fill_color(*self.mapi_light_grey) for col, size in zip(columns_names, columns_sizes): self.pdf.rect( self.pdf.get_x(), self.pdf.get_y(), size, self.cell_height, style="FD", ) self.pdf.set_text_color(*self.mapi_dark_grey) self.pdf.cell(size, self.cell_height, col, align="L") self.pdf.set_xy(self.margin, self.pdf.get_y() + self.cell_height) self.pdf.set_draw_color(*self.mapi_light_grey) self.pdf.set_fill_color(*self.mapi_light_light_green) for row in rows: for i, (col, size) in enumerate(zip(row, columns_sizes)): if i == 0 and row_header: self.pdf.set_draw_color(*self.mapi_light_grey) self.pdf.set_fill_color(*self.mapi_light_grey) self.pdf.rect( self.pdf.get_x(), self.pdf.get_y(), size, self.cell_height, style="FD", ) self.pdf.set_text_color(*self.mapi_dark_grey) if i == 0 and row_header: self.pdf.set_draw_color(*self.mapi_light_grey) self.pdf.set_fill_color(*self.mapi_light_light_green) self.pdf.cell(size, self.cell_height, col, align="L") self.pdf.set_xy(self.margin, self.pdf.get_y() + self.cell_height) def _read_stats_file(self, filename) -> Dict[str, Any]: file_path = os.path.join(self.output_path, filename) with self.io_handler.open_rt(file_path) as fin: return io.json_load(fin) def _read_gcp_stats_file(self, filename): file_path = os.path.join(self.output_path, "ground_control_points.json") with self.io_handler.open_rt(file_path) as fin: return io.json_load(fin) def _make_section(self, title: str) -> None: self.pdf.set_font("Helvetica", "B", self.h1) self.pdf.set_text_color(*self.mapi_dark_grey) self.pdf.cell(0, self.margin, title, align="L") self.pdf.set_xy(self.margin, self.pdf.get_y() + 1.5 * self.margin) def _make_subsection(self, title: str) -> None: self.pdf.set_xy(self.margin, self.pdf.get_y() - 0.5 * self.margin) self.pdf.set_font("Helvetica", "B", self.h2) self.pdf.set_text_color(*self.mapi_dark_grey) self.pdf.cell(0, self.margin, title, align="L") self.pdf.set_xy(self.margin, self.pdf.get_y() + self.margin) def _make_centered_image(self, image_path: str, desired_height: float) -> None: with tempfile.TemporaryDirectory() as tmp_local_dir: local_image_path = os.path.join(tmp_local_dir, os.path.basename(image_path)) with self.io_handler.open(local_image_path, "wb") as fwb: with self.io_handler.open(image_path, "rb") as f: fwb.write(f.read()) width, height = PIL.Image.open(local_image_path).size resized_width = width * desired_height / height if resized_width > self.total_size: resized_width = self.total_size desired_height = height * resized_width / width self.pdf.image( local_image_path, self.pdf.get_x() + self.total_size / 2 - resized_width / 2, self.pdf.get_y(), h=desired_height, ) self.pdf.set_xy(self.margin, self.pdf.get_y() + desired_height + self.margin) def make_title(self) -> None: # title self.pdf.set_font("Helvetica", "B", self.title_size) self.pdf.set_text_color(*self.mapi_light_green) self.pdf.cell(0, self.margin, "ODM Quality Report", align="C") self.pdf.set_xy(self.margin, self.title_size) # version number version_file = os.path.abspath( os.path.join(os.path.dirname(__file__), "../../../../../VERSION")) try: with open(version_file, 'r') as f: version = f.read().strip() except Exception as e: # indicate we don't know the version version = "unknown" logger.warning(f"Invalid ODM version {version_file}: " + str(e)) self.pdf.set_font("Helvetica", "", self.small_text) self.pdf.set_text_color(*self.mapi_dark_grey) self.pdf.cell(0, self.margin, f"Processed with ODM version {version}", align="R") self.pdf.set_xy(self.margin, self.pdf.get_y() + 2 * self.margin) def make_dataset_summary(self) -> None: self._make_section("Dataset Summary") rows = [ #["Dataset", self.dataset_name], ["Date", self.stats["processing_statistics"]["date"]], [ "Area Covered", f"{self.stats['processing_statistics']['area']/1e6:.6f} km²", ], [ "Processing Time", self.stats[self.odm_stat]['total_time_human'] if self.odm_stat in self.stats else \ f"{self.stats['processing_statistics']['steps_times']['Total Time']:.2f} seconds", ], ["Capture Start", self.stats["processing_statistics"]["start_date"]], ["Capture End", self.stats["processing_statistics"]["end_date"]], ] self._make_table(None, rows, True) self.pdf.set_xy(self.margin, self.pdf.get_y() + self.margin) def _has_meaningful_gcp(self) -> bool: return (self.stats["reconstruction_statistics"]["has_gcp"] and "average_error" in self.stats["gcp_errors"]) def make_processing_summary(self) -> None: self._make_section("Processing Summary") rec_shots, init_shots = ( self.stats["reconstruction_statistics"] ["reconstructed_shots_count"], self.stats["reconstruction_statistics"]["initial_shots_count"], ) rec_points, init_points = ( self.stats["reconstruction_statistics"] ["reconstructed_points_count"], self.stats["reconstruction_statistics"]["initial_points_count"], ) geo_string = [] if self.stats["reconstruction_statistics"]["has_gps"]: geo_string.append("GPS") if self._has_meaningful_gcp(): geo_string.append("GCP") ratio_shots = rec_shots / init_shots * 100 if init_shots > 0 else -1 rows = [ [ "Reconstructed Images", f"{rec_shots} over {init_shots} shots ({ratio_shots:.1f}%)", ], [ "Reconstructed Points (Sparse)", f"{rec_points} over {init_points} points ({rec_points/init_points*100:.1f}%)", ], # [ # "Reconstructed Components", # f"{self.stats['reconstruction_statistics']['components']} component", # ], [ "Detected Features", f"{self.stats['features_statistics']['detected_features']['median']:,} features", ], [ "Reconstructed Features", f"{self.stats['features_statistics']['reconstructed_features']['median']:,} features", ], ["Geographic Reference", " and ".join(geo_string)], ] # Dense (if available) if self.stats.get('point_cloud_statistics'): if self.stats['point_cloud_statistics'].get('dense'): rows.insert(2, [ "Reconstructed Points (Dense)", f"{self.stats['point_cloud_statistics']['stats']['statistic'][0]['count']:,} points" ]) # GSD (if available) if self.odm_stat in self.stats and self.stats[self.odm_stat].get( 'average_gsd'): rows.insert(3, [ "Average Ground Sampling Distance (GSD)", f"{self.stats[self.odm_stat]['average_gsd']:.1f} cm" ]) row_gps_gcp = [" / ".join(geo_string) + " errors"] geo_errors = [] if self.stats["reconstruction_statistics"]["has_gps"]: geo_errors.append( f"{self.stats['gps_errors']['average_error']:.2f}") if self._has_meaningful_gcp(): geo_errors.append( f"{self.stats['gcp_errors']['average_error']:.2f}") row_gps_gcp.append(" / ".join(geo_errors) + " meters") rows.append(row_gps_gcp) self._make_table(None, rows, True) self.pdf.set_xy(self.margin, self.pdf.get_y() + self.margin / 2) topview_height = 110 topview_grids = [ f for f in self.io_handler.ls(self.output_path) if f.startswith("topview") ] self._make_centered_image( os.path.join(self.output_path, topview_grids[0]), topview_height) self.pdf.set_xy(self.margin, self.pdf.get_y() + self.margin) def make_processing_time_details(self) -> None: self._make_section("Processing Time Details") columns_names = list( self.stats["processing_statistics"]["steps_times"].keys()) formatted_floats = [] for v in self.stats["processing_statistics"]["steps_times"].values(): formatted_floats.append(f"{v:.2f} sec.") rows = [formatted_floats] self._make_table(columns_names, rows) self.pdf.set_xy(self.margin, self.pdf.get_y() + 2 * self.margin) def make_gcp_error_details(self): self._make_section("Ground Control Point Error") gcp_stats = self._read_gcp_stats_file("ground_control_points.json") rows = [] column_names = ["ID", "Error X (m)", "Error Y (m)", "Error Z (m)"] for gcp in gcp_stats: row = [gcp["id"]] row.append(f"{gcp['error'][0]:.3f}") row.append(f"{gcp['error'][1]:.3f}") row.append(f"{gcp['error'][2]:.3f}") rows.append(row) self._make_table(column_names, rows) self.pdf.set_xy(self.margin, self.pdf.get_y() + self.margin / 2) def make_gps_details(self) -> None: self._make_section("GPS/GCP/3D Errors Details") # GPS table_count = 0 for error_type in ["gps", "gcp", "3d"]: rows = [] columns_names = [error_type.upper(), "Mean", "Sigma", "RMS Error"] if "average_error" not in self.stats[error_type + "_errors"]: continue for comp in ["x", "y", "z"]: row = [comp.upper() + " Error (meters)"] row.append( f"{self.stats[error_type + '_errors']['mean'][comp]:.3f}") row.append( f"{self.stats[error_type +'_errors']['std'][comp]:.3f}") row.append( f"{self.stats[error_type +'_errors']['error'][comp]:.3f}") rows.append(row) rows.append([ "Total", "", "", f"{self.stats[error_type +'_errors']['average_error']:.3f}", ]) self._make_table(columns_names, rows) self.pdf.set_xy(self.margin, self.pdf.get_y() + self.margin / 2) table_count += 1 if table_count > 0: abs_error_type = "gps" if table_count == 2 else "gcp" a_ce90 = self.stats[abs_error_type + "_errors"].get("ce90", 0) a_le90 = self.stats[abs_error_type + "_errors"].get("le90", 0) r_ce90 = self.stats["3d_errors"].get("ce90", 0) r_le90 = self.stats["3d_errors"].get("le90", 0) rows = [] if a_ce90 > 0 and a_le90 > 0: rows += [[ "Horizontal Accuracy CE90 (meters)", f"{a_ce90:.3f}", f"{r_ce90:.3f}" if r_ce90 > 0 else "-", ], [ "Vertical Accuracy LE90 (meters)", f"{a_le90:.3f}", f"{r_le90:.3f}" if r_le90 > 0 else "-", ]] if rows: if table_count > 2: self.add_page_break() self._make_table(["", "Absolute", "Relative"], rows, True) self.pdf.set_xy(self.margin, self.pdf.get_y() + self.margin / 2) # rows = [] # columns_names = [ # "GPS Bias", # "Scale", # "Translation", # "Rotation", # ] # for camera, params in self.stats["camera_errors"].items(): # bias = params["bias"] # s, t, R = bias["scale"], bias["translation"], bias["rotation"] # rows.append( # [ # camera, # f"{s:.2f}", # f"{t[0]:.2f} {t[1]:.2f} {t[2]:.2f}", # f"{R[0]:.2f} {R[1]:.2f} {R[2]:.2f}", # ] # ) # self._make_table(columns_names, rows) self.pdf.set_xy(self.margin, self.pdf.get_y() + self.margin / 2) def make_features_details(self) -> None: self._make_section("Features Details") heatmap_height = 60 heatmaps = [ f for f in self.io_handler.ls(self.output_path) if f.startswith("heatmap") ] self._make_centered_image(os.path.join(self.output_path, heatmaps[0]), heatmap_height) if len(heatmaps) > 1: logger.warning("Please implement multi-model display") columns_names = ["", "Min.", "Max.", "Mean", "Median"] rows = [] for comp in ["detected_features", "reconstructed_features"]: row = [comp.replace("_", " ").replace("features", "").capitalize()] for t in columns_names[1:]: row.append( f"{self.stats['features_statistics'][comp][t.replace('.', '').lower()]:.0f}" ) rows.append(row) self._make_table(columns_names, rows) self.pdf.set_xy(self.margin, self.pdf.get_y() + self.margin) def make_reconstruction_details(self) -> None: self._make_section("Reconstruction Details") rows = [ [ "Average Reprojection Error (normalized / pixels / angular)", (f"{self.stats['reconstruction_statistics']['reprojection_error_normalized']:.2f} / " f"{self.stats['reconstruction_statistics']['reprojection_error_pixels']:.2f} / " f"{self.stats['reconstruction_statistics']['reprojection_error_angular']:.5f}" ), ], [ "Average Track Length", f"{self.stats['reconstruction_statistics']['average_track_length']:.2f} images", ], [ "Average Track Length (> 2)", f"{self.stats['reconstruction_statistics']['average_track_length_over_two']:.2f} images", ], ] self._make_table(None, rows, True) self.pdf.set_xy(self.margin, self.pdf.get_y() + self.margin / 1.5) residual_histogram_height = 60 residual_histogram = [ f for f in self.io_handler.ls(self.output_path) if f.startswith("residual_histogram") ] self._make_centered_image( os.path.join(self.output_path, residual_histogram[0]), residual_histogram_height, ) self.pdf.set_xy(self.margin, self.pdf.get_y() + self.margin) def make_camera_models_details(self) -> None: self._make_section("Camera Models Details") for camera, params in self.stats["camera_errors"].items(): residual_grids = [ f for f in self.io_handler.ls(self.output_path) if f.startswith("residuals_" + str(camera.replace("/", "_"))) ] if not residual_grids: continue initial = params["initial_values"] optimized = params["optimized_values"] names = [""] + list(initial.keys()) rows = [] rows.append(["Initial"] + [f"{x:.4f}" for x in initial.values()]) rows.append(["Optimized"] + [f"{x:.4f}" for x in optimized.values()]) self._make_subsection(camera) self._make_table(names, rows) self.pdf.set_xy(self.margin, self.pdf.get_y() + self.margin / 2) residual_grid_height = 100 self._make_centered_image( os.path.join(self.output_path, residual_grids[0]), residual_grid_height) def make_rig_cameras_details(self) -> None: if len(self.stats["rig_errors"]) == 0: return self._make_section("Rig Cameras Details") columns_names = [ "Translation X", "Translation Y", "Translation Z", "Rotation X", "Rotation Y", "Rotation Z", ] for rig_camera_id, params in self.stats["rig_errors"].items(): initial = params["initial_values"] optimized = params["optimized_values"] rows = [] r_init, t_init = initial["rotation"], initial["translation"] r_opt, t_opt = optimized["rotation"], optimized["translation"] rows.append([ f"{t_init[0]:.4f} m", f"{t_init[1]:.4f} m", f"{t_init[2]:.4f} m", f"{r_init[0]:.4f}", f"{r_init[1]:.4f}", f"{r_init[2]:.4f}", ]) rows.append([ f"{t_opt[0]:.4f} m", f"{t_opt[1]:.4f} m", f"{t_opt[2]:.4f} m", f"{r_opt[0]:.4f}", f"{r_opt[1]:.4f}", f"{r_opt[2]:.4f}", ]) self._make_subsection(rig_camera_id) self._make_table(columns_names, rows) self.pdf.set_xy(self.margin, self.pdf.get_y() + self.margin / 2) def make_tracks_details(self) -> None: self._make_section("Tracks Details") matchgraph_height = 80 matchgraph = [ f for f in self.io_handler.ls(self.output_path) if f.startswith("matchgraph") ] self._make_centered_image( os.path.join(self.output_path, matchgraph[0]), matchgraph_height) histogram = self.stats["reconstruction_statistics"][ "histogram_track_length"] start_length, end_length = 2, 10 row_length = ["Length"] for length, _ in sorted(histogram.items(), key=lambda x: int(x[0])): if int(length) < start_length or int(length) > end_length: continue row_length.append(length) row_count = ["Count"] for length, count in sorted(histogram.items(), key=lambda x: int(x[0])): if int(length) < start_length or int(length) > end_length: continue row_count.append(f"{count}") self._make_table(None, [row_length, row_count], True) self.pdf.set_xy(self.margin, self.pdf.get_y() + self.margin) def add_page_break(self) -> None: self.pdf.add_page("P") def make_survey_data(self): self._make_section("Survey Data") self._make_centered_image( os.path.join(self.output_path, "overlap.png"), 90) self._make_centered_image( os.path.join(self.output_path, "overlap_diagram_legend.png"), 3) self.pdf.set_xy(self.margin, self.pdf.get_y() + self.margin / 2) def _add_image_label(self, text): self.pdf.set_font_size(self.small_text) self.pdf.text( self.pdf.get_x() + self.total_size / 2 - self.pdf.get_string_width(text) / 2, self.pdf.get_y() - 5, text) def make_preview(self): ortho = os.path.join(self.output_path, "ortho.png") dsm = os.path.join(self.output_path, "dsm.png") dtm = os.path.join(self.output_path, "dtm.png") count = 0 if os.path.isfile(ortho) or os.path.isfile(dsm): self._make_section("Previews") if os.path.isfile(ortho): self._make_centered_image( os.path.join(self.output_path, ortho), 110) self._add_image_label("Orthophoto") count += 1 if os.path.isfile(dsm) and self.stats.get('dsm_statistics'): self._make_centered_image(os.path.join(self.output_path, dsm), 110) self._add_image_label("Digital Surface Model") self._make_centered_image( os.path.join(self.output_path, "dsm_gradient.png"), 4) self.pdf.set_font_size(self.small_text) min_text = "{:,.2f}m".format( self.stats['dsm_statistics']['min']) max_text = "{:,.2f}m".format( self.stats['dsm_statistics']['max']) self.pdf.text(self.pdf.get_x() + 40, self.pdf.get_y() - 5, min_text) self.pdf.text( self.pdf.get_x() + 40 + 110.5 - self.pdf.get_string_width(max_text), self.pdf.get_y() - 5, max_text) count += 1 if os.path.isfile(dtm) and self.stats.get('dtm_statistics'): if count >= 2: self.add_page_break() self._make_centered_image(os.path.join(self.output_path, dtm), 110) self._add_image_label("Digital Terrain Model") self._make_centered_image( os.path.join(self.output_path, "dsm_gradient.png"), 4) self.pdf.set_font_size(self.small_text) min_text = "{:,.2f}m".format( self.stats['dtm_statistics']['min']) max_text = "{:,.2f}m".format( self.stats['dtm_statistics']['max']) self.pdf.text(self.pdf.get_x() + 40, self.pdf.get_y() - 5, min_text) self.pdf.text( self.pdf.get_x() + 40 + 110.5 - self.pdf.get_string_width(max_text), self.pdf.get_y() - 5, max_text) self.pdf.set_xy(self.margin, self.pdf.get_y() + self.margin) return True def generate_report(self) -> None: self.make_title() self.make_dataset_summary() self.make_processing_summary() self.add_page_break() if self.make_preview(): self.add_page_break() if os.path.isfile(os.path.join(self.output_path, "overlap.png")): self.make_survey_data() self.make_gps_details() if os.path.isfile( os.path.join(self.output_path, "ground_control_points.json")): self.make_gcp_error_details() self.add_page_break() self.make_features_details() self.make_reconstruction_details() self.add_page_break() self.make_tracks_details() self.make_camera_models_details()
def export_weeks_to_pdf(schedule_ref: Schedule, title_text: str, add_date: bool, file_path: str, font_name: str, font_path: str, encoding: str, start: datetime.date, end: datetime.date, color_a: QColor, color_b: QColor, progress=None) -> None: """ Method for exports to PDF file """ file = QFileInfo(file_path) # pdf pdf = FPDF(orientation="L") # encoding if encoding == "UTF-8": pdf.add_font(font_name, "", font_path, uni=True) else: pdf.add_font(font_name, "", font_path) pdf.set_doc_option("core_fonts_encoding", encoding) # processing week_step = 100 / (end - start).days / 7 count = 0 pdf.set_font(font_name) while True: pdf.add_page() schedule = schedule_ref.create_week_schedule( start, start + datetime.timedelta(days=6)) indexes = schedule.indexes() table_widget = schedule_editor_window.ScheduleTableWidget() table_widget.set_schedule(schedule) start += datetime.timedelta(days=6) x, y = float(pdf.get_x()), float(pdf.get_y()) w = float(pdf.w) - 2 * float(pdf.get_x()) h = float(pdf.h) - 2 * float(pdf.get_y()) - 6 pdf.set_auto_page_break(True, margin=y) title = 10 title_page = title_text if add_date: start_week = (start + datetime.timedelta(days=-6)).strftime("%d.%m.%Y") end_week = start.strftime("%d.%m.%Y") title_page += f". {start_week} - {end_week}" pdf.set_font_size(14) pdf.cell(w, title, txt=title_page, align="C", border=0) h -= title first_column, first_row = 4, 4 step_column = (w - first_row) / 8 step_row = (h - first_column) / 6 i = 0 while i < 7: j = 0 while j < 9: if i == 0 and j == 0: # upper-left cell pdf.set_xy(x, y + title) pdf.cell(first_column, first_row, border=1) j += 1 elif i == 0: # top cells with time pdf.set_xy(x + first_row + step_column * (j - 1), y + title) pdf.set_font_size(8) pdf.cell(step_column, first_row, txt=TimePair.time_start_end(j - 1), align="C", border=1) j += 1 elif j == 0: # left cells with days of the week pdf.set_xy( x, y + title + first_column + step_row * (i - 1) + step_row) pdf.rotate(90) pdf.set_font_size(8) pdf.cell(step_row, first_row, txt=str(DaysOfWeek.value_of(i - 1)), align="C", border=1) pdf.rotate(0) j += 1 else: # cells inside the table pdf.set_xy(x + first_row + step_column * (j - 1), y + title + first_column + step_row * (i - 1)) simple_row = (step_row / indexes[i - 1]) prev_x, prev_y = pdf.get_x(), pdf.get_y() start_index = sum(indexes[r] for r in range(i - 1)) number_row = 0 for m in range(start_index, start_index + indexes[i - 1]): item = table_widget.item(m, j - 1) if item is not None: x_span_count = table_widget.columnSpan(m, j - 1) y_span_count = table_widget.rowSpan(m, j - 1) pdf.set_xy(prev_x, prev_y + number_row * simple_row) # pdf.cell(step_column * x_span_count, # simple_row * y_span_count, # border=1) day, number, duration = i - 1, j - 1, x_span_count pairs = schedule.pairs_by_index( day, number, duration, number_row) # select color for cell if all(pair["subgroup"].get_subgroup() == SubgroupPairAttrib.Common for pair in pairs): # common pdf.cell(step_column * x_span_count, simple_row * y_span_count, border=1) elif all(pair["subgroup"].get_subgroup() == SubgroupPairAttrib.A for pair in pairs): # A subgroup pdf.set_fill_color(color_a.red(), color_a.green(), color_a.blue()) pdf.cell(step_column * x_span_count, simple_row * y_span_count, border=1, fill=1) elif all(pair["subgroup"].get_subgroup() == SubgroupPairAttrib.B for pair in pairs): # B subgroup pdf.set_fill_color(color_b.red(), color_b.green(), color_b.blue()) pdf.cell(step_column * x_span_count, simple_row * y_span_count, border=1, fill=1) else: # A and B subgroup prev_x = pdf.get_x() prev_y = pdf.get_y() toggle = True row = 5 column = math.ceil(step_column * x_span_count / step_row * row) for t in range(column): for n in range(row): pdf.set_xy( prev_x + t * step_column * x_span_count / column, prev_y + n * step_row / row) if toggle: color = color_a toggle = False else: color = color_b toggle = True pdf.set_fill_color( color.red(), color.green(), color.blue()) pdf.cell(step_column * x_span_count / column, simple_row * y_span_count / row, border=0) pdf.set_xy(prev_x, prev_y) pdf.cell(step_column * x_span_count, simple_row * y_span_count, border=1) if len(pairs) != 0: text = "\n".join(str(pair) for pair in pairs) draw_text( pdf, x + first_row + step_column * (j - 1), y + title + first_column + step_row * (i - 1) + simple_row * number_row, step_column * x_span_count, simple_row * y_span_count, text) number_row += 1 pdf.set_xy(prev_x, prev_y) j += 1 # old # pairs = schedule.pairs_by_index(i - 1, j - 1, 1) \ # + schedule.pairs_by_index(i - 1, j - 1, 2) # # max_duration = max([1, *[pair["time"].duration() for pair in pairs]]) # # # select color for cell # if all(pair["subgroup"].get_subgroup() == SubgroupPairAttrib.Common # for pair in pairs): # # common # pdf.cell(step_column * max_duration, # step_row, # border=1) # elif all(pair["subgroup"].get_subgroup() == SubgroupPairAttrib.A # for pair in pairs): # # A subgroup # pdf.set_fill_color(color_a.red(), color_a.green(), color_a.blue()) # pdf.cell(step_column * max_duration, # step_row, # border=1, # fill=1) # elif all(pair["subgroup"].get_subgroup() == SubgroupPairAttrib.B # for pair in pairs): # # B subgroup # pdf.set_fill_color(color_b.red(), color_b.green(), color_b.blue()) # pdf.cell(step_column * max_duration, # step_row, # border=1, # fill=1) # else: # # A and B subgroup # prev_x = pdf.get_x() # prev_y = pdf.get_y() # # toggle = True # # row = 5 # column = math.ceil(step_column * max_duration / step_row * row) # # for m in range(column): # for n in range(row): # pdf.set_xy(prev_x + m * step_column * max_duration / column, # prev_y + n * step_row / row) # # if toggle: # color = color_a # toggle = False # else: # color = color_b # toggle = True # # pdf.set_fill_color(color.red(), color.green(), color.blue()) # pdf.cell(step_column * max_duration / column, # step_row / row, # border=0, # fill=1) # pdf.set_xy(prev_x, prev_y) # pdf.cell(step_column * max_duration, # step_row, # border=1) # text = "" # for pair in pairs: # text += str(pair) + "\n" # # if text != "": # draw_text(pdf, # x + first_row + step_column * (j - 1), # y + title + first_column + step_row # * (i - 1), # step_column * max_duration, # step_row, # text) # j += max_duration i += 1 if progress is not None: count += 1 progress.setValue(week_step * count) if progress.wasCanceled(): break start += datetime.timedelta(days=1) if end <= start: break pdf.output(file.absoluteFilePath())
class PDFPrinter: xCurrent = 0 yCurrent = 0 def __init__(self, path): self.path = path self.pdf = FPDF('P', 'mm', 'A4') self.page_setup() def page_setup(self): self.pdf.add_font("NotoSans", style="", fname="NotoSans-Regular.ttf", uni=True) self.pdf.add_font("NotoSans", style="B", fname="NotoSans-Bold.ttf", uni=True) self.pdf.add_font("NotoSans", style="I", fname="NotoSans-Italic.ttf", uni=True) self.pdf.add_font("NotoSans", style="BI", fname="NotoSans-BoldItalic.ttf", uni=True) self.pdf.set_font("NotoSans", size=8) self.pdf.add_page() def set_coordintates(self, x, y): self.xCurrent = x self.yCurrent = y def print_photo(self, img, pi): x = self.xCurrent y = self.yCurrent self.pdf.image(img, x, y, PhotoSize.w, PhotoSize.h) # Write name below the image xText = x yText = y + PhotoSize.h + 2 # photo height + spacing (TODO get rid of magic constant) self.pdf.set_font_size(6) # TODO get rid of magic constant self.pdf.text(xText, yText, pi.name + ", " + pi.before_arrival) # TODO handle too long names def print_person_info(self, pi): self.pdf.set_font_size(8) # TODO get rid of magic constant x = self.xCurrent y = self.yCurrent self.pdf.text(x + TextDeltas.xName, y + TextDeltas.yName, pi.name) self.pdf.text(x + TextDeltas.xNationality, y + TextDeltas.yNationality, pi.nationality) self.pdf.text(x + TextDeltas.xFaculty, y + TextDeltas.yFaculty, pi.faculty) self.pdf.text(x + TextDeltas.xSection, y + TextDeltas.ySection, pi.section) self.pdf.text(x + TextDeltas.xBirthday, y + TextDeltas.yBirthday, pi.birthday.strftime("%d")) # day self.pdf.text(x + TextDeltas.xBirthday + CardSpacing.dayDelta, y + TextDeltas.yBirthday, pi.birthday.strftime("%m")) # month self.pdf.text(x + TextDeltas.xBirthday + 2 * CardSpacing.dayDelta, y + TextDeltas.yBirthday, pi.birthday.strftime("%y")) # year self.pdf.text(x + TextDeltas.xValidity, y + TextDeltas.yValidity, pi.validity.strftime("%d")) # day self.pdf.text(x + TextDeltas.xValidity + CardSpacing.dayDelta, y + TextDeltas.yValidity, pi.validity.strftime("%m")) # month self.pdf.text(x + TextDeltas.xValidity + 2 * CardSpacing.dayDelta, y + TextDeltas.yValidity, pi.validity.strftime("%y")) # year def print_delimiter(self, x, y): delimX1 = x - ContentSpacing.xSpacing / 2 delimX2 = delimX1 + ContentSpacing.xSpacing / 2 delimX0 = delimX1 + (delimX2 - delimX1) / 2 delimY1 = y - ContentSpacing.ySpacing / 3 delimY2 = delimY1 + ContentSpacing.ySpacing / 2 delimY0 = delimY1 + (delimY2 - delimY1) / 2 self.pdf.line(delimX1, delimY0, delimX2, delimY0) self.pdf.line(delimX0, delimY1, delimX0, delimY2) def output(self): self.pdf.output(self.path, "F") def add_page(self): self.pdf.add_page()
print '>>>multisig bitcoin receiving address:', addr_multi print '>>>private keys: ' for x in range(len(priv)): print x+1, priv[x] print pub[x] print '>>>multisignature script:', script print '>>>Creating paper wallet image file..' ############################## pdf=FPDF('P','mm', 'A4') # Portrait, use milimeters pdf.add_page() pdf.set_font('Times', '', 20) # pdf.image(jpeg,0,0,210,297) #dimensions of a4 in mm pdf.cell (0, 10,str(mkeys)+'-of-'+str(nkeys)+': multisignature bitcoin paper wallet %s / page 1' % addr_multi[:6] ,1,1,'C') pdf.set_font_size(13) pdf.cell(0, 32, 'multisig address: ' + addr_multi,1,1) im, im_h, im_w = qrc(addr_multi) img = Image.new( 'RGB', (im_w,im_h), "white") img.paste(im,(0,0)) img.save('qrcode.jpg') h_qr = 21 pdf.image('qrcode.jpg',169,h_qr,30,30) os.remove('qrcode.jpg') h_qr +=1 for x in range(len(priv)): h_qr+=31 pdf.cell(0,31,'Private ' + str(x+1)+': '+wif[x],1,1,'L') im, im_h, im_w = qrc(wif[x])
class kut2fpdf(object): _document = None # Aquí se irán guardando los datos del documento logger = None _xml = None _xml_data = None _page_orientation = None _page_size = None _bottom_margin = None _left_margin = None _right_margin = None _top_margin = None _page_top = {} _data_row = None # Apunta a la fila actual en data _parser_tools = None _avalible_fonts = None _unavalible_fonts = None design_mode = None _actual_data_line = None _no_print_footer = False _actual_section_size = None increase_section_size = None last_detail = False actual_data_level = None last_data_processed = None prev_level = None draws_at_header = None detailn = None name_ = None _actual_append_page_no = None reset_page_count = None def __init__(self): self.logger = logging.getLogger("kut2fpdf") checkDependencies({"fpdf": "pyfpdf"}) from pineboolib.plugins.kugar.parsertools import parsertools self._parser_tools = parsertools() self._avalible_fonts = [] self._unavalible_fonts = [] self.design_mode = FLSettings().readBoolEntry("ebcomportamiento/kugar_debug_mode") self._actual_data_line = None self._no_print_footer = False self.increase_section_size = 0 self.actual_data_level = 0 self.prev_level = -1 self.draws_at_header = {} self.detailn = {} self.name_ = None self._actual_append_page_no = 0 self.reset_page_count = False self.new_page = False """ Convierte una cadena de texto que contiene el ".kut" en un pdf y retorna la ruta a este último. @param name. Nombre de ".kut". @param kut. Cadena de texto que contiene el ".kut". @param data. Cadena de texto que contiene los datos para ser rellenados en el informe. @return Ruta a fichero pdf. """ def parse(self, name, kut, data, report = None, flags = []): try: self._xml = self._parser_tools.loadKut(kut) except Exception: self.logger.exception( "KUT2FPDF: Problema al procesar %s.kut", name) return False try: self._xml_data = load2xml(data) except Exception: self.logger.exception("KUT2FPDF: Problema al procesar xml_data") return False self.name_ = name self.setPageFormat(self._xml) # self._page_orientation = # self._page_size = if report is None: from fpdf import FPDF self._actual_append_page_no = -1 self._document = FPDF(self._page_orientation, "pt", self._page_size) for f in self._document.core_fonts: self.logger.debug("KUT2FPDF :: Adding font %s", f) self._avalible_fonts.append(f) else: self._document = report # Seteamos rutas a carpetas con tipos de letra ... # Cargamos las fuentes disponibles next_page_break = (flags[2] == 1) if len(flags) == 3 else True page_append = (flags[1] == 1) if len(flags) > 1 else False page_display = (flags[0] == 1) if len(flags) > 0 else False if page_append: self.prev_level = -1 self.last_detail = False page_break = False if self.new_page: page_break = True self.new_page = False if self.reset_page_count: self.reset_page_no() self.reset_page_count = False if self.design_mode: print("Append", page_append) print("Display", page_display) print("Page break", next_page_break) if next_page_break: self.reset_page_count = True if page_display: self.new_page = True self.processDetails(not page_break) #FIXME:Alguno valores no se encuentran for p in self._document.pages.keys(): page_content = self._document.pages[p]["content"] for h in self.draws_at_header.keys(): page_content = page_content.replace(h, str(self.draws_at_header[h])) self._document.pages[p]["content"] = page_content #print(self.draws_at_header.keys()) self._document.set_title(self.name_) self._document.set_author("Pineboo - kut2fpdf plugin") return self._document def get_file_name(self): import os pdf_name = aqApp.tmp_dir() pdf_name += "/%s_%s.pdf" % (self.name_, datetime.datetime.now().strftime("%Y%m%d%H%M%S")) if os.path.exists(pdf_name): os.remove(pdf_name) if self._document is not None: self._document.output(pdf_name, 'F') return pdf_name else: return None """ Indica el techo para calcular la posición de los objetos de esa sección. @return Número con el techo de la página actual. """ def topSection(self): return self._page_top[str(self._document.page_no())] """ Actualiza el valor del techo de la página actual. Se suele actualizar al procesar una sección. @param value. Numero que elspecifica el nuevo techo. """ def setTopSection(self, value): self._actual_section_size = value - self.topSection() self._page_top[str(self._document.page_no())] = value """ Añade una nueva página al documento. """ def newPage(self, data_level, add_on_header = True): self._document.add_page(self._page_orientation) self._page_top[str(self._document.page_no())] = self._top_margin self._document.set_margins(self._left_margin, self._top_margin, self._right_margin) # Lo dejo pero no se nota nada self._no_print_footer = False if self.design_mode: self.draw_margins() self._actual_section_size = 0 self._actual_append_page_no += 1 if self.design_mode: print("Nueva página", self.number_pages()) #l_ini = data_level #l_end = self.prev_level #if l_ini == l_end: # l_end = l_end + 1 #if l_ini <= l_end: # for l in range(l_ini , l_end): # print(l) # self.processSection("AddOnHeader", str(l)) pg_headers = self._xml.findall("PageHeader") for ph in pg_headers: if self.number_pages() == 0 or ph.get("PrintFrequency") == "1": ph_level = ph.get("Level") if ph.get("Level") is not None else None self.processSection("PageHeader", ph_level) break if add_on_header and not self.number_pages() == 0: for l in range(data_level + 1): self.processSection("AddOnHeader", str(l)) #Por ahora se omite detail header """ Procesa las secciones details con sus correspondientes detailHeader y detailFooter. """ def processDetails(self, keep_page = None): # Procesamos la cabecera si procede .. top_level = 0 level = 0 first_page_created = keep_page if keep_page is not None and self._document.page_no() > 0 else False rows_array = self._xml_data.findall("Row") for data in rows_array: self._actual_data_line = data level = int(data.get("level")) if level > top_level: top_level = level if not first_page_created: self.newPage(level) first_page_created = True if rows_array[len(rows_array) - 1] is data: self.last_detail = True if level < self.prev_level: for l in range(level + 1, self.prev_level + 1): self.processData("DetailFooter", self.last_data_processed, l) if not str(level) in self.detailn.keys(): self.detailn[str(level)] = 0 else: self.detailn[str(level)] += 1 if level > self.prev_level: self.processData("DetailHeader", data, level) self.processData("Detail", data, level) self.last_data_processed = data self.prev_level = level if not self._no_print_footer: for l in reversed(range(top_level + 1)): self.processData("DetailFooter", data, l) """ Paso intermedio que calcula si detailHeader + detail + detailFooter entran en el resto de la ṕagina. Si no es así crea nueva página. @param section_name. Nombre de la sección a procesar. @param data. Linea de datos a procesar. @param data_level. Nivel de seccion. """ def processData(self, section_name, data, data_level): self.actual_data_level = data_level listDF = self._xml.findall(section_name) data_size = len(listDF) for dF in listDF: draw_if = dF.get("DrawIf") show = True if draw_if: show = data.get(draw_if) if dF.get("Level") == str(data_level) and show not in ("None", "False"): if section_name in ("DetailHeader","Detail"): heightCalculated = self._parser_tools.getHeight(dF) + self.topSection() if section_name is "DetailHeader": for detail in self._xml.findall("Detail"): if detail.get("Level") == str(data_level): heightCalculated += self._parser_tools.getHeight(detail) for dFooter in self._xml.findall("DetailFooter"): if dFooter.get("Level") == str(data_level): heightCalculated += self._parser_tools.getHeight(dFooter) #for addFooter in self._xml.findall("AddOnFooter"): # if addFooter.get("Level") == str(data_level): # heightCalculated += self._parser_tools.getHeight(addFooter) pageFooter = self._xml.get("PageFooter") if pageFooter: if self._document.page_no() == 1 or pageFooter.get("PrintFrecuency") == "1": heightCalculated += self._parser_tools.getHeight(pageFooter) heightCalculated += self._bottom_margin if heightCalculated > self._document.h: # Si nos pasamos self._no_print_footer = True #Vemos el tope por abajo limit_bottom = self._document.h - self._parser_tools.getHeight(self._xml.get("AddOnFooter")) actual_size = self._parser_tools.getHeight(dF) + self.topSection() if (actual_size > limit_bottom + 2) or self.last_detail: # +2 se usa de margen extra self.processSection("AddOnFooter", str(data_level)) self.newPage(data_level) self.processXML(dF, data) if dF.get("NewPage") == "true" and not self.last_detail: self.newPage(data_level, False) break #Se ejecuta una sola instancia """ Procesa las secciones fuera de detail @param name. Nombre de la sección a procesar. """ def processSection(self, name, level=0): sec_list = self._xml.findall(name) sec_ = None for s in sec_list: if s.get("Level") == str(level) or s.get("Level") is None: sec_ = s if sec_ is not None: if sec_.get("PrintFrequency") == "1" or self._document.page_no() == 1 or name in ("AddOnHeader","AddOnFooter"): self.processXML(sec_) """ Procesa un elemento de xml. @param xml: El elemento a procesar. @param. data: Linea de datos afectada. """ def processXML(self, xml, data=None): fix_height = True if data is None: data = self._actual_data_line if self.design_mode: print("Procesando", xml.tag, data.get("level")) size_updated = False if xml.tag == "DetailFooter": if xml.get("PlaceAtBottom") == "true": self.setTopSection(self._document.h - self._parser_tools.getHeight(xml)) size_updated = True if xml.tag == "PageFooter": fix_height = False self.fix_extra_size() #Sirve para actualizar la altura con lineas que se han partido porque son muy largas for label in xml.iter("Label"): self.processText(label, data, fix_height) for field in xml.iter("Field"): self.processText(field, data, fix_height) for special in xml.iter("Special"): self.processText(special, data, fix_height, xml.tag) for calculated in xml.iter("CalculatedField"): self.processText(calculated, data, fix_height, xml.tag) #Busco draw_at_header en DetailFooter y los meto también if xml.tag == "DetailHeader": detail_level = xml.get("Level") for df in self._xml.iter("DetailFooter"): if df.get("Level") == detail_level: for cf in df.iter("CalculatedField"): if cf.get("DrawAtHeader") == "true": header_name = "%s_header_%s_%s" % (self.detailn[detail_level], detail_level, cf.get("Field")) self.draws_at_header[header_name] = "" self.processText(cf, data, fix_height, xml.tag) for line in xml.iter("Line"): self.processLine(line, fix_height) if not size_updated: self.setTopSection(self.topSection() + self._parser_tools.getHeight(xml)) def fix_extra_size(self): if self.increase_section_size > 0: self.setTopSection(self.topSection() + self.increase_section_size) self.increase_section_size = 0 """ Procesa una linea. @param xml. Sección de xml a procesar. @param fix_height. Ajusta la altura a los .kut originales, excepto el pageFooter. """ def processLine(self, xml, fix_height=True): color = xml.get("Color") r = 0 if not color else int(color.split(",")[0]) g = 0 if not color else int(color.split(",")[1]) b = 0 if not color else int(color.split(",")[2]) style = int(xml.get("Style")) width = int(xml.get("Width")) X1 = self.calculateLeftStart(xml.get("X1")) X1 = self.calculateWidth(X1, 0, False) X2 = self.calculateLeftStart(xml.get("X2")) X2 = self.calculateWidth(X2, 0, False) # Ajustar altura a secciones ya creadas Y1 = int(xml.get("Y1")) + self.topSection() Y2 = int(xml.get("Y2")) + self.topSection() if fix_height: Y1 = self._parser_tools.ratio_correction(Y1) Y2 = self._parser_tools.ratio_correction(Y2) self._document.set_line_width(width) self._document.set_draw_color(r, g, b) dash_length = 1 space_length = 1 if style == 2: dash_length = 20 space_length = 20 elif style == 3: dash_length = 10 space_length = 10 self._document.dashed_line(X1, Y1, X2, Y2, dash_length, space_length) #else: # self._document.line(X1, Y1, X2, Y2) """ Comprueba si excedemos el margen izquierdo de la página actual @param x. Posición a comprobar. @return Valor corregido, si procede. """ def calculateLeftStart(self, x): return self._parser_tools.ratio_correction(int(x)) + self._left_margin """ Comprueba si excedemos el margen derecho de la página actual @param x. Posición a comprobar. @return Valor corregido, si procede. """ def calculateWidth(self, width, pos_x, fix_ratio = True): width = int(width) if fix_ratio: width = self._parser_tools.ratio_correction(int(width)) ret_ = width limit = self._document.w - self._right_margin if pos_x + width > limit: ret_ = limit - pos_x return ret_ """ Procesa una etiqueta. Esta puede ser un campo calculado, una etiqueta, un campo especial o una imagen. @param xml. Sección de xml a procesar. @param fix_height. Ajusta la altura a los .kut originales, excepto el pageFooter. """ def processText(self, xml, data_row=None, fix_height=True, section_name = None): is_image = False is_barcode = False text = xml.get("Text") borderColor = xml.get("BorderColor") field_name = xml.get("Field") # x,y,W,H se calcula y corrigen aquí para luego estar correctos en los diferentes destinos posibles W = int(xml.get("Width")) H = self._parser_tools.getHeight(xml) x = int(xml.get("X")) y = int(xml.get("Y")) + self.topSection() # Añade la altura que hay ocupada por otras secciones if fix_height: y = self._parser_tools.ratio_correction(y) # Corrige la posición con respecto al kut original data_type = xml.get("DataType") if xml.tag == "Field" and data_row is not None: text = data_row.get(field_name) elif xml.tag == "Special": if text == "": if xml.get("Type") == "1": text = "PageNo" text = self._parser_tools.getSpecial( text, self._actual_append_page_no) calculation_type = xml.get("CalculationType") if calculation_type is not None and xml.tag != "Field": if calculation_type == "6": function_name = xml.get("FunctionName") try: nodo = self._parser_tools.convertToNode(data_row) from pineboolib.pncontrolsfactory import aqApp ret_ = aqApp.call(function_name, [nodo, field_name]) if ret_ is False: return else: text = str(ret_) except Exception: self.logger.exception( "KUT2FPDF:: Error llamando a function %s", function_name) return elif calculation_type == "1": text = self._parser_tools.calculate_sum(field_name, self.last_data_processed, self._xml_data, self.actual_data_level) elif calculation_type in ("5"): if data_row is None: data_row = self._xml_data[0] text = data_row.get(field_name) if data_type is not None: text = self._parser_tools.calculated(text, int(data_type), xml.get("Precision"), data_row) if data_type == "5": is_image = True elif data_type == "6": is_barcode = True if xml.get("BlankZero") == "1" and text is not None: res_ = re.findall(r'\d+', text) res_ = "".join(res_) if int(res_) == 0: return if text is not None and text.startswith(filedir("../tempdata")): is_image = True negValueColor = xml.get("NegValueColor") Currency = xml.get("Currency") commaSeparator = xml.get("CommaSeparator") dateFormat = xml.get("DateFormat") if is_image: self.draw_image(x, y, W, H, xml, text) elif is_barcode: self.draw_barcode(x, y, W, H, xml, text) else: level = data_row.get("level") if level and str(level) in self.detailn.keys(): val = "%s_header_%s_%s" % ( self.detailn[str(level)], level,field_name) if xml.get("DrawAtHeader") == "true" and level: if section_name == "DetailHeader": val = "" self.drawText(x, y, W, H, xml, val) print(level, section_name, val, text) if section_name == "DetailFooter" and xml.get("DrawAtHeader") == "true": self.draws_at_header[val] = text print("Añadiendo a", val, text, level) else: self.drawText(x, y, W, H, xml, text) """ Dibuja un campo texto en la página. @param x. Pos x de la etiqueta. @param y. Pos y de la etiqueta. @param W. Anchura de la etiqueta. @param H. Altura de la etiqueta. @param xml. Sección del xml afectada. @param txt. Texto calculado de la etiqueta a crear. """ def drawText(self, x, y, W, H, xml, txt): if txt in ("None", None): return txt = self._parser_tools.restore_text(txt) resizeable = False if xml.get("ChangeHeight") == "1": resizeable = True height_resized = False orig_x = x orig_y = y orig_W = W orig_H = H # Corregimos margenes: x = self.calculateLeftStart(x) W = self.calculateWidth(W, x) #bg_color = xml.get("BackgroundColor").split(",") fg_color = self.get_color(xml.get("ForegroundColor")) self._document.set_text_color(fg_color[0], fg_color[1], fg_color[2]) #self._document.set_draw_color(255, 255, 255) #if xml.get("BorderStyle") == "1": # FIXME: Hay que ajustar los margenes #font_name, font_size, font_style font_style = "" font_size = int(xml.get("FontSize")) font_name_orig = xml.get("FontFamily").lower() if xml.get("FontFamily") is not None else "helvetica" font_name = font_name_orig font_w = xml.get("FontWeight") if font_w in (None, "50"): #Normal font_w = 100 elif int(font_w) >= 65: font_style += "B" font_w = 100 fontI = xml.get("FontItalic") fontU = xml.get("FontUnderlined") # FIXME: hay que ver si es así background_color = self.get_color(xml.get("BackgroundColor")) #if background_color != [255,255,255]: #Los textos que llevan fondo no blanco van en negrita # font_style += "B" if fontI == "1": font_style += "I" if fontU == "1": font_style += "U" font_full_name = "%s%s" % (font_name, font_style) if font_full_name not in self._avalible_fonts: font_found = self._parser_tools.find_font(font_full_name) if font_found: self.logger.warning("KUT2FPDF::Añadiendo el tipo de letra %s (%s)", font_full_name, font_found) self._document.add_font(font_full_name, "", font_found, True) self._avalible_fonts.append(font_full_name) else: if font_full_name not in self._unavalible_fonts: self.logger.warning("KUT2FPDF:: No se encuentra el tipo de letra %s. Sustituido por helvetica%s." %(font_full_name, font_style)) self._unavalible_fonts.append(font_full_name) font_name = "helvetica" if font_name is not font_name_orig and font_name_orig.lower().find("narrow") > -1: font_w = 85 self._document.set_font(font_name, font_style, font_size) self._document.set_stretching(font_w) # Corregir alineación VAlignment = xml.get("VAlignment") # 0 izquierda, 1 centrado,2 derecha HAlignment = xml.get("HAlignment") layout_direction = xml.get("layoutDirection") start_section_size = self._actual_section_size result_section_size = 0 #Miramos si el texto sobrepasa el ancho array_text = [] array_n = [] text_lines = [] if txt.find("\n") > -1: for t in txt.split("\n"): array_n.append(t) if array_n: #Hay saltos de lineas ... for n in array_n: text_lines.append(n) else: #No hay saltos de lineas text_lines.append(txt) for tl in text_lines: str_width = self._document.get_string_width(tl) if str_width > W + 2 and xml.tag !="Label" and resizeable: #Una linea es mas larga que el ancho del campo(Dejando 2 de juego) height_resized = True array_text = self.split_text(tl, W) else: array_text.append(tl) #calculated_h = orig_H * len(array_text) self.drawRect(orig_x, orig_y, orig_W, orig_H, xml) processed_lines = 0 extra_size = 0 for actual_text in array_text: if actual_text is None: continue processed_lines += 1 if processed_lines > 1: extra_size += font_size + 2 if HAlignment == "1": # sobre X # Centrado x = x + (W / 2) - (self._document.get_string_width(actual_text) / 2) #x = x + (W / 2) - (str_width if not height_resized else W / 2) elif HAlignment == "2": # Derecha x = x + W - self._document.get_string_width(actual_text) - 2 # -2 de margen #x = x + W - str_width if not height_resized else W else: # Izquierda x = x + 2 if VAlignment == "1": # sobre Y # Centrado #y = (y + ((H / 2) / processed_lines)) + (((self._document.font_size_pt / 2) / 2) * processed_lines) y = ( orig_y + ( orig_H / 2))+ ((self._document.font_size_pt / 2) /2) elif VAlignment == "2": # Abajo y = orig_y + orig_H - font_size else: # Arriba y = orig_y + font_size y = y + extra_size if self.design_mode: self.write_debug(self.calculateLeftStart(orig_x), y, "Hal:%s, Val:%s, T:%s st:%s" % (HAlignment, VAlignment, txt, font_w), 6, "green") if xml.tag == "CalculatedField": self.write_debug(self.calculateLeftStart(orig_x), y, "CalculatedField:%s, Field:%s" % (xml.get("FunctionName"), xml.get("Field")), 3, "blue") self._document.text(x, y, actual_text) result_section_size += start_section_size result_section_size = result_section_size - start_section_size if self.increase_section_size < extra_size: #Si algun incremento extra hay superior se respeta self.increase_section_size = extra_size def split_text(self, texto, limit_w): list_ = [] linea_ = None for t in texto.split(" "): if linea_ is None and t == "": continue if linea_ is not None: if self._document.get_string_width(linea_ + t) > limit_w: list_.append(linea_) linea_ = "" else: linea_ = "" linea_ += "%s " % t list_.append(linea_) return list_ """ Dibuja un cuadrado en la página actual. @param x. Pos x del cuadrado. @param y. Pos y del cuadrado. @param W. Anchura del cuadrado. @param H. Altura del cuadrado. """ def get_color(self, value): value = value.split(",") r = None g = None b = None if len(value) == 3: r = int(value[0]) g = int(value[1]) b = int(value[2]) else: r = int(value[0:2]) g = int(value[3:5]) b = int(value[6:8]) return [r,g,b] def drawRect(self, x, y, W, H, xml = None): style_ = "" border_color = None bg_color = None line_width = self._document.line_width border_width = 0.2 #Calculamos borde y restamos del ancho orig_x = x orig_y = y orig_w = W x = self.calculateLeftStart(orig_x) W = self.calculateWidth(W, x) if xml is not None and not self.design_mode: if xml.get("BorderStyle") == "1": border_color = self.get_color(xml.get("BorderColor")) self._document.set_draw_color(border_color[0], border_color[1], border_color[2]) style_ += "D" bg_color = self.get_color(xml.get("BackgroundColor")) self._document.set_fill_color(bg_color[0], bg_color[1], bg_color[2]) style_ = "F" + style_ border_width = int(xml.get("BorderWidth") if xml.get("BorderWidth") else 0.2) else: self.write_cords_debug(x,y,W,H, orig_x, orig_w) style_ = "D" self._document.set_draw_color(0, 0, 0) if style_ is not "": self._document.set_line_width(border_width) self._document.rect(x, y, W, H, style_) self._document.set_line_width(line_width) self._document.set_xy(orig_x, orig_y) #self._document.set_draw_color(255, 255, 255) #self._document.set_fill_color(0, 0, 0) def write_cords_debug(self, x, y, w, h, ox, ow): self.write_debug(x,y,"X:%s Y:%s W:%s H:%s orig_x:%s, orig_W:%s" % (round(x, 2),round(y, 2),round(w, 2),round(h, 2), round(ox, 2), round(ow, 2)), 2, "red") def write_debug(self, x,y,text, h, color = None): orig_color = self._document.text_color r = None g = None b = None current_font_family = self._document.font_family current_font_size = self._document.font_size_pt current_font_style = self._document.font_style if color is "red": r = 255 g = 0 b = 0 elif color is "green": r = 0 g = 255 b = 0 elif color is "blue": r = 0 g = 0 b = 255 self._document.set_text_color(r,g,b) self._document.set_font_size(4) self._document.text(x, y + h, text) self._document.text_color = orig_color #self._document.set_xy(orig_x, orig_y) self._document.set_font(current_font_family, current_font_style, current_font_size) """ Inserta una imagen en la página actual. @param x. Pos x de la imagen. @param y. Pos y de la imagen. @param W. Anchura de la imagen. @param H. Altura de la imagen. @param xml. Sección del xml afectada. @param file_name. Nombr del fichero de tempdata a usar """ def draw_image(self, x, y, W, H, xml, file_name): import os if not file_name.lower().endswith(".png"): file_name = self._parser_tools.parseKey(file_name) if file_name is not None and os.path.exists(file_name): x = self.calculateLeftStart(x) W = self.calculateWidth(W, x) self._document.image(file_name, x, y, W, H, "PNG") def draw_barcode(self, x, y, W, H, xml, text): if text == "None": return from pineboolib.fllegacy.flcodbar import FLCodBar file_name = aqApp.tmp_dir() file_name += "/%s.png" % (text) type = xml.get("CodBarType") if not os.path.exists(file_name): bar_code = FLCodBar(text) #Code128 if type is not None: type = bar_code.nameToType(type.lower()) bar_code.setType(type) pix = bar_code.pixmap() if not pix.isNull(): pix.save(file_name, "PNG") self.draw_image(x , y, W, H, xml, file_name) """ Define los parámetros de la página @param xml: Elemento xml con los datos del fichero .kut a procesar """ def setPageFormat(self, xml): custom_size = None self._bottom_margin = int(xml.get("BottomMargin")) self._left_margin = int(xml.get("LeftMargin")) self._right_margin = int(xml.get("RightMargin")) self._top_margin = int(xml.get("TopMargin")) page_size = int(xml.get("PageSize")) page_orientation = xml.get("PageOrientation") if page_size in [30, 31]: custom_size = [int(xml.get("CustomHeightMM")), int(xml.get("CustomWidthMM"))] self._page_orientation = "P" if page_orientation == "0" else "L" self._page_size = self._parser_tools.converPageSize( page_size, int(page_orientation), custom_size) # devuelve un array def draw_margins(self): self.draw_debug_line(0 + self._left_margin , 0, 0+ self._left_margin , self._page_size[1]) #Vertical derecha self.draw_debug_line(self._page_size[0] - self._right_margin , 0, self._page_size[0] - self._right_margin , self._page_size[1])#Vertical izquierda self.draw_debug_line(0, 0 + self._top_margin, self._page_size[0], 0 + self._top_margin) #Horizontal superior self.draw_debug_line(0, self._page_size[1] - self._bottom_margin, self._page_size[0], self._page_size[1] - self._bottom_margin) #Horizontal inferior def draw_debug_line(self, X1, Y1, X2, Y2, title= None, color="GREY"): dash_length = 2 space_length = 2 r = 0 g = 0 b = 0 if color == "GREY": r = 220 g = 220 b = 220 self._document.set_line_width(1) self._document.set_draw_color(r, g, b) self._document.dashed_line(X1, Y1, X2, Y2, dash_length, space_length) def number_pages(self): return self._actual_append_page_no if self._actual_append_page_no > 0 else 0 def reset_page_no(self): self._actual_append_page_no = -1
def setPDF(self): '''Generates a PDF document and sets self.pdf to it This function should be the final function called before comitting to the DB. All other variables should be set when this function is called. Args: none. Returns: a success of failure message ''' pdf = FPDF() course = Course.query.filter_by(number=self.course_number, version=self.course_version).first() pdf.add_page() pdf.set_font('Arial', 'B', 16) pdf.cell(0, 5, 'CS' + str(self.course_number) + ' ' + course.name, ln=1, align='C') pdf.cell(0, 5, 'Course Syllabus', ln=1, align='C') pdf.ln(5) pdf.set_font_size(14) for instructor in self.instructorList: pdf.cell(0, 10, instructor.name, ln=1, align='C') pdf.ln(5) pdf.set_font('') pdf.cell(0, 5, self.semester + ' ' + str(self.year) + ' Semester', ln=1, align='C') #TODO, make section number a string in database, add check # for section to determine campus pdf.cell(0, 5, 'Kent Campus, Section: ' + str(self.section), ln=1, align='C') #TODO, fix once room number and building are moved to syllabus #TODO, revamp meeting_time once we get delimiter solved if self.meeting_time and course.room and course.building: pdf.cell(0, 5, self.meeting_time + ', ' + str(course.room) + ' ' + course.building, ln=1, align='C') else: pdf.cell(0, 10, 'This is an online course, there is no meeting times', ln=1, align='C') pdf.ln(10) #TODO, optional, once in db #if introduction != null: #pdf.set_font_size(14) #pdf.cell(0,5, 'Instructor Introduction', ln=1) #pdf.set_font_size(12) #pdf.multi_cell(0,5, 'Walker is a very nice man who is teaching this course') #pdf.ln(5) pdf.set_font_size(14) pdf.cell(0, 5, 'Contact Information', ln=1) pdf.set_font_size(12) for instructor in self.instructorList: pdf.cell(0, 5, 'Email: ' + instructor.email, ln=1) pdf.cell(0, 5, 'Phone: ' + str(instructor.phone), ln=1) #TODO, include office room in database, nevermind have it included in office hours #pdf.cell(0,5, 'Office: #####', ln=1) if instructor.perfered_office_hours: pdf.cell(0, 5, 'Office Hours: ' + instructor.perfered_office_hours, ln=1) pdf.ln(5) pdf.set_font_size(14) pdf.cell(0, 5, 'Course Description from the University Catalog', ln=1) pdf.set_font_size(12) if course.description: pdf.multi_cell( 0, 5, 'CS' + str(self.course_number) + ' ' + course.name + ': ' + course.description) else: pdf.multi_cell( 0, 5, 'CS' + str(self.course_number) + ' ' + course.name + ': ') if (course.prerequisites != None): pdf.cell(0, 5, 'Prerequisite: ' + course.prerequisites, ln=1) pdf.cell( 0, 5, 'Students without the proper prerequisite(s) risk being deregistered from the class', ln=1) pdf.ln(5) pdf.set_font_size(14) pdf.cell(0, 5, 'Course Learning Outcomes', ln=1) pdf.set_font_size(12) pdf.cell(0, 5, 'By the end of this course, you should be able to:', ln=1) for clo in course.clos: pdf.multi_cell(0, 5, clo.general) pdf.ln(5) if (course.is_core): pdf.ln(5) pdf.multi_cell( 0, 5, 'This coourse may be used to satisfy a Kent Core requirement. The Kent Core as a whole is intended to broaden intellectual perspectives, foster ethical and humanitarian values, and prepare students for responsible citizenship and productive careers.' ) if (course.is_diversity == 1): pdf.ln(5) pdf.multi_cell( 0, 5, 'This course may be used to satisfy the University Diversity requirement. Diversity courses provide opportunities for students to learn about such matters as the history, culture, values and notable achievements of people other than those of their own national origin, ethnicity, religion, sexual orientaiton, age, gender, physical and mental ability, and social class. Diversity courses also provide opportunities to examine problems and issues that may arise from differences, and opportunities to learn how to deal constructively with them.' ) if (course.is_wi == 1): pdf.ln(5) pdf.multi_cell( 0, 5, 'This course may be used to satisfy the Writing Intensive Course (WIC) requirement. The purpose of a writing-intensive course is to assist students in becoming effective writers within their major discipline. A WIC requires a substantial amount of writing, provides opportunities for guided revision, and focuses on writing forms and standards used in the professional life of the discipline.' ) if (course.is_elr == 1): pdf.ln(5) pdf.multi_cell( 0, 5, 'This course may be used to fulfill the university\'s Experiential Learning Requirement (ELR) which provides students with the opportunity to initiate lifelong learning through the development and application of academic knowledge and skills in new or different settings. Experiential learning can occur through civic engagement, creative and artistic activities, practical experiences, research, and study abroad/away.' ) #TODO, required should be moved to course, no syllabus if (self.required_materials != None): pdf.ln(5) pdf.set_font_size(14) pdf.cell(0, 5, 'Required Materials', ln=1) pdf.set_font_size(12) pdf.multi_cell(0, 5, self.required_materials) if (self.optional_materials != None): pdf.ln(5) pdf.set_font_size(14) pdf.cell(0, 5, 'Optional Materials', ln=1) pdf.set_font_size(12) pdf.cell(0, 5, self.optional_materials, ln=1) #TODO, enforce notnull dates / policies if (self.grading_policy != None): pdf.ln(5) pdf.set_font_size(14) pdf.cell(0, 5, 'Grading Policy', ln=1) pdf.multi_cell(0, 5, self.grading_policy) pdf.ln(5) pdf.set_font_size(14) pdf.cell(0, 5, 'Registration Date', ln=1) pdf.set_font_size(12) pdf.multi_cell( 0, 5, 'University policy requires all students to be officially registered in each class they are attending. Students who are not officially registered for a course by published deadlines should not be attending classes and will not receive credit or a grade for the course. Each student must confirm enrollment by checking his/her class schedule (using Student Tools in FlashLine) prior to the deadline indicated. Registration errors must be corrected prior to the deadline.' ) pdf.cell(0, 5, 'https://www.kent.edu/registrar/fall-your-time-register', ln=1) pdf.ln(5) pdf.set_font_size(14) pdf.cell(0, 5, 'Withdrawl Date', ln=1) pdf.set_font_size(12) pdf.cell(0, 5, 'The course withdrawal deadline is found below', ln=1) pdf.cell(0, 5, 'https://www.kent.edu/registrar/spring-important-dates', ln=1) pdf.ln(5) if self.attendance_policy: pdf.set_font_size(14) pdf.cell(0, 5, 'Attendance Policy', ln=1) pdf.set_font_size(12) pdf.multi_cell(0, 5, self.attendance_policy) pdf.ln(5) #pdf.cell(0,5, 'Attendance Policy goes here', ln=1) pdf.set_font_size(14) pdf.cell(0, 5, 'Student Accessability Services', ln=1) pdf.set_font_size(12) pdf.multi_cell(0, 5, self.Students_with_disabilities) #pdf.cell(0,5, 'Important info here', ln=1) pdf.ln(5) pdf.set_font_size(14) pdf.cell(0, 5, 'Academic Integrity', ln=1) pdf.set_font_size(12) pdf.multi_cell(0, 5, self.cheating_policy) #pdf.cell(0,5, "Don't plagarize bad", ln=1) if (self.extra_policies != None): pdf.ln(5) pdf.set_font_size(14) pdf.cell(0, 5, 'Extra Policies', ln=1) pdf.set_font_size(12) pdf.multi_cell(0, 5, self.extra_policies) #pdf.output('course.pdf', 'F') # Convert Model Data to HTML #syllabusHTML = 'TODO' # = convertToHTML() # Convert HTML to PDF #syllabusPDF = 'TODO' # = pdfKitFunction(syllabusHTML) self.pdf = pdf.output(dest='S').encode('latin-1') #pdf.output('wolves.pdf', 'F') #file = open('wolves.pdf', 'rb').read() #self.pdf = file #db.session.query(Syllabus) \ #.filter_by(self) \ #.update({"pdf": (file)}) #db.session.commit() if (self.pdf != None): return 'success' else: return 'failure'
def prepare_report(): """ Master method, creates a folder with the user's desired filename, and writes a PDF report with salient information. Also creates a line chart and a bar chart! :return: Nothing. """ # Get list of folders in user's desired directory. Check to make sure that they entered valid information. try: local_list = os.listdir(report_dest) except NotADirectoryError: print("Wrong Directory Specification.") quit() # Setting final destination of the report. global final_destination final_destination = Path(report_dest + "REPORT/") # Checking to make sure that we are able to create a folder at the user's desired filepath. # If invalid, program quits. if local_list.count("REPORT") == 0: try: os.mkdir(final_destination) except FileNotFoundError: print("Incorrect filepath.") quit() # Begin writing to PDF. pdf = FPDF(orientation="P", unit='cm', format="Letter") pdf.set_font('Arial') pdf.set_author("Chris Matthew Cyril") pdf.set_font_size(12) pdf.add_page(orientation="P") pdf.set_title(title="REPORT") pdf.write(h=0, txt='GENERATED REPORT -- ' + str(datetime.datetime.now())) pdf.write(h=1, txt="\nDataBank source was found in: " + DataBank_source) pdf.write(h=1, txt="\nBMAL Filepath: " + BMAL_filepath) pdf.write(h=1, txt="\nCYCLE Filepath: " + CYC_filepath) pdf.write(h=1, txt="\nThis report can be found at: " + str(final_destination)) pdf.set_text_color(0, 255, 255) pdf.write( h=1, txt="\nGitHub Link To Code", link="https://github.com/ChrisMatthewCyril/Needleman/tree/Version3.0") pdf.set_text_color(0, 0, 0) pdf.write(h=1, txt="\nCalculated Gene Deviation Score: " + str(gene_deviation_score)) pdf.write(h=1, txt="\n Number of Gene pairs: " + str(num_pairs)) pdf.add_page(orientation="P") pdf.set_font('Arial', style='B') pdf.cell(w=14, h=1, txt="Compared Files", border=1, ln=0, align='L', fill=False) pdf.cell(w=6, h=1, txt="Needleman-Wunsch Score", border=1, ln=1, align='L', fill=False) pdf.set_font('Arial', style='') # Making table of gene pairings with alignment scores. for first_file, second_file in gene_pair_scores: pdf.cell(w=14, h=1, txt=first_file + " vs " + second_file, border=1, ln=0, align='L', fill=False) pdf.cell(w=6, h=1, txt=str(gene_pair_scores[(first_file, second_file)]), border=1, ln=1, align='R', fill=False) # Making bar and line charts. barchart_path = plot_bar() linechart_path = plot_line() # Adding the bar and line chart images from their links on the computer. pdf.add_page(orientation='landscape') pdf.image(barchart_path, h=20, w=27) pdf.image(linechart_path, h=20, w=27) pdf.add_page(orientation='portrait') pdf.write( h=1, txt="Thanks for an amazing quarter, Professor Schiffer and the TA's!\n" "Best, as always,\nChris Matthew Cyril :)") pdf.add_page(orientation='portrait') # pdf.write(h=1, txt=getAnalysis()) pdf_location = final_destination / report_filename pdf.output(str(pdf_location) + ".pdf", dest='F').encode('latin-1') # Thank you! Close-out message. print("Thanks for an amazing quarter, Professor Schiffer and the TA's!\n" "Best, as always,\nChris Matthew Cyril :) \n" "Don't forget to pick up your report! You can find it at: " + str(pdf_location))
# font defination title_font_data = data['pdf']['fonts']['title'] text_font_data = data['pdf']['fonts']['text'] # font for title if title_font_data['type'] == 'embeded': pdf.add_font(title_font_data['name'], '', os.path.abspath('.') + '/app/pdf/' + title_font_data['path'], uni=True) title_font = title_font_data['name'] # font for plain text if text_font_data['type'] == 'embeded': pdf.add_font(text_font_data['name'], '', os.path.abspath('.') + '/app/pdf/' + text_font_data['path'], uni=True) text_font = text_font_data['name'] # header section # left pdf.set_font(title_font, '', font_size['header_title']) pdf.cell(1, line_height['section'] + 1, data['header']['name'], ln=2) pdf.set_font_size(font_size['header_sub_title']) pdf.set_text_color(grey) pdf.cell(1, line_height['text'] + 1, data['header']['title'], ln=2) pdf.set_font_size(font_size['text'] + 2) online_text = data['pdf']['online']['text'] pdf.cell(pdf.get_string_width(online_text), line_height['text'] + 1, online_text, ln=0) pdf.set_text_color(*blue) pdf.cell(1, line_height['text'] + 1, data['pdf']['online']['url'], ln=2, link=data['pdf']['online']['url']) header_y = pdf.get_y() # right pdf.set_y(page_size['top'] - 1) pdf.set_x(page_size['end_x']) pdf.set_font(text_font, '', font_size['text']) pdf.set_text_color(black) pdf.cell(1, line_height['text'] - 0.5, data['about']['location'], ln=2, align='R') pdf.cell(1, line_height['text'] - 0.5, data['about']['phone'], ln=2, align='R')
def export_full_to_pdf(schedule_ref: Schedule, title_text: str, file_path: str, font_name: str, font_path: str, encoding: str, progress=None) -> None: """ Method for exports to PDF file """ file = QFileInfo(file_path) # pdf pdf = FPDF(orientation="L") # encoding if encoding == "UTF-8": pdf.add_font(font_name, "", font_path, uni=True) else: pdf.add_font(font_name, "", font_path) pdf.set_doc_option("core_fonts_encoding", encoding) pdf.set_font(font_name) pdf.add_page() x, y = float(pdf.get_x()), float(pdf.get_y()) w = float(pdf.w) - 2 * float(pdf.get_x()) h = float(pdf.h) - 2 * float(pdf.get_y()) - 6 pdf.set_auto_page_break(True, margin=y) title = 10 pdf.set_font_size(14) pdf.cell(w, title, txt=title_text, align="C", border=0) h -= title first_column, first_row = 4, 4 step_column = (w - first_row) / 8 step_row = (h - first_column) / 6 indexes = schedule_ref.indexes() table_widget = schedule_editor_window.ScheduleTableWidget() table_widget.set_schedule(schedule_ref) # processing week_step = 100 / 7 count = 0 i = 0 while i < 7: j = 0 while j < 9: if i == 0 and j == 0: # upper-left cell pdf.set_xy(x, y + title) pdf.cell(first_column, first_row, border=1) j += 1 elif i == 0: # top cells with time pdf.set_xy(x + first_row + step_column * (j - 1), y + title) pdf.set_font_size(8) pdf.cell(step_column, first_row, txt=TimePair.time_start_end(j - 1), align="C", border=1) j += 1 elif j == 0: # left cells with days of the week pdf.set_xy( x, y + title + first_column + step_row * (i - 1) + step_row) pdf.rotate(90) pdf.set_font_size(8) pdf.cell(step_row, first_row, txt=str(DaysOfWeek.value_of(i - 1)), align="C", border=1) pdf.rotate(0) j += 1 else: # cells inside the table pdf.set_xy(x + first_row + step_column * (j - 1), y + title + first_column + step_row * (i - 1)) simple_row = (step_row / indexes[i - 1]) prev_x, prev_y = pdf.get_x(), pdf.get_y() start_index = sum(indexes[r] for r in range(i - 1)) number_row = 0 for m in range(start_index, start_index + indexes[i - 1]): item = table_widget.item(m, j - 1) if item is not None: x_span_count = table_widget.columnSpan(m, j - 1) y_span_count = table_widget.rowSpan(m, j - 1) pdf.set_xy(prev_x, prev_y + number_row * simple_row) pdf.cell(step_column * x_span_count, simple_row * y_span_count, border=1) text = item.text() if text != "": draw_text( pdf, x + first_row + step_column * (j - 1), y + title + first_column + step_row * (i - 1) + simple_row * number_row, step_column * x_span_count, simple_row * y_span_count, text) number_row += 1 pdf.set_xy(prev_x, prev_y) j += 1 i += 1 if progress is not None: count += 1 progress.setValue(week_step * count) if progress.wasCanceled(): break pdf.output(file.absoluteFilePath())
def printNovelPDF(novid_id): print("printNovelPDF") folderPID = "D:\\novel-result\\" now = datetime.today().strftime("%Y-%m-%d_%H-%M") col1 = 10 cnx = mysql.connector.connect(host="127.0.0.1", port=3306, user="******", password="******", database='bangna5_covid') try: pdf = FPDF('P', 'mm', 'A4') pdf.add_font('TH Sarabun New', '', 'd:\\lab-result\\Sarabun\\THSarabunNew.ttf', uni=True) pdf.set_font('TH Sarabun New') pdf.add_page() sql = "Select patient_fullname,patient_age,visit_date,nation,occupation,mobile,address,home_type,symptom,disease,status_vaccine_covid,pregnant,pregnant_week,mnc_hn_no,address From bangna5_covid.t_novel Where novel_id = '" + str( novid_id) + "' " curMy = cnx.cursor() curMy.execute(sql) records = curMy.fetchall() for rowMy in records: patient_fullname = rowMy[0] patient_age = rowMy[1] visit_date = rowMy[2] nation = rowMy[3] occupation = rowMy[4] mobile = rowMy[5] address = rowMy[6] home_type = rowMy[7] symptom = rowMy[8] #8 disease = rowMy[9] status_vaccine_covid = rowMy[10] pregnant = rowMy[11] pregnant_week = rowMy[12] mnc_hn_no = rowMy[13] address = rowMy[14] #mnc_hn_no=rowMy[15] #pregnant=rowMy[6] #pregnant=rowMy[6] #pregnant=rowMy[6] #pregnant=rowMy[6] #pregnant=rowMy[6] #pdf.text(col3,145, "send date "+datetime.today().strftime("%d/%m/%Y %H:%M")) deleteFileinFolder(folderPID, str(mnc_hn_no) + "_" + str(now) + ".pdf") pdf.set_font_size(12) pdf.text(col1, 10, "แบบรายงานผู้ป่วยโรคติดเชื้อโคโรนา 2019 ฉบับย่อ") pdf.set_font_size(10) pdf.text(150, 10, "Code") pdf.text(150, 16, "Novelcorona 3") pdf.line(10, 14, 180, 14) pdf.text(col1, 20, "ข้อมูลทั่วไป") pdf.text(140, 25, "เลขบัตรประชาชน/passport .........................") pdf.text( col1, 30, "ชื่อ-นามสกุล ....................................... เพศ ชาย หญิง อายุ ..... ปี สัญชาติ ............" ) pdf.text( col1, 35, "ประเภท PUI ผู้สัมผัสใกล้ชิดผู้ติดเชื้อ การค้นหา/สำรวจเชิงรุก Sentinel surveilance อื่นๆ ................" ) pdf.text( col1, 40, "อาชีพ (ระบุลักษณะงาน เช่น บุคลากรทางการแพทย์ งานที่สัมผัสกับนักท่องเที่ยว/ขาวต่างชาติ) ..................................." ) pdf.text( col1, 45, "เบอร์โทรศัพท์ .......................... สถานที่ทำงาน/สถานศึกษา ............................." ) pdf.text( col1, 50, "ที่อยู่ขณะป่วยในประเทศไทย ชื่อสถานที่ ..................................................." ) pdf.text( col1, 55, "หมู่ .......... ตำบล ............... อำเภอ .............. จังหวัด ..........................." ) pdf.text( col1, 60, "ลักษณะที่พักอาสัย บ้านเดี่ยว ตึกแถว/ทาวน์เฮ้าส์ หอพัก/คอนโด/ห้องเช่า" ) pdf.text( col1, 65, " พักห้องรวมกับคนจำนวนมาก เช่น แคมป์ก่อสร้าง หอผู้ป่วยใน รพ. อื่นๆ ระบุ ......................." ) print(folderPID + "\\" + str(mnc_hn_no) + "_" + str(now) + ".pdf") pdf.output( folderPID + "\\" + str(mnc_hn_no) + "_" + str(now) + ".pdf", 'F') time.sleep(0.01) except mysql.connector.Error as e: print(e) finally: if cnx.is_connected(): curMy.close() cnx.close()
def Print_PDF(train, name, age, gender, address, adhr, pnr, DoJ, starting, destination, staus, seatNo, coach, mobl, email): addhar = 'XXXXXXXX' for i in str(adhr)[8:12]: addhar += i mobile = 'XXXXXX' for i in str(mobl)[6:10]: mobile += i from fpdf import FPDF document = FPDF(orientation='P', unit='mm', format='A4') document.add_page() document.set_margins(10, 5, 10) document.set_font("arial", 'U', size=28) document.cell(130, 25, txt=f"Indian Railways", ln=1, align='R') document.cell(1, 5, txt="", ln=10) document.set_font("arial", 'B', size=24) document.cell(130, 30, txt=train, ln=1, align='R') document.cell(1, 28, txt="", ln=10) document.set_font("Arial", "B", size=18) document.cell(5, 15, txt=f"PNR : {pnr} Aadhaar : {addhar}", ln=3) document.set_font_size(15) document.cell( 15, 15, txt= f"Name : {name} DoB\\Gender : {age} {gender.capitalize()[0]}", ln=6) document.cell( 25, 15, txt= f"Coach Number: {coach} Seat No : {seatNo} Status : {staus}", ln=9) document.cell(1, 30, txt="", ln=10) document.set_font("Arial", size=14) document.cell(35, 15, txt=f"Date of Journey : {DoJ}", ln=12) document.cell( 45, 15, txt= f"Starting Junction : {starting} Destination Junction : {destination}", ln=15) document.cell(1, 30, txt="", ln=10) document.cell( 55, 15, txt=f"Mobile Number : {mobile} E-Mail ID : {email}", ln=18) document.cell(65, 15, txt=f"Address : {address}", ln=21) document.output(f"{pnr}.pdf") return f"Your ticket have been Booked!! and would be send at {email}"
def generateInvoice(self,Inid,date,name,add,item,qty,unitprice,amt): from fpdf import FPDF pdf = FPDF() pdf.add_page() pdf.set_font("courier", size=25) pdf.cell(200, 10, txt="Guru Sampoorna", ln=1, align="C") pdf.set_line_width(1) pdf.rect(10,5,190,275) pdf.set_line_width(0) pdf.line(10,40,200,40) pdf.set_font('courier',size=12) pdf.set_left_margin(150) pdf.cell(200,10,txt="Bengali chouraha ",ln=1,align='F') pdf.cell(200,10,txt="Mob No- 8962727182",ln=1,align='F') pdf.set_left_margin(10) pdf.cell(200,5,txt=" ",ln=1,align='F') pdf.cell(200,10,txt=" Invoice No - {}\n ".format(Inid),ln=1,align='F') pdf.cell(200,10,txt=" Date - {}".format(date),ln=1,align='F') pdf.cell(200,10,txt=" Customer Name - {}".format(name),ln=1,align='F') pdf.cell(200,10,txt=" Customer Address - {}".format(add),ln=1,align='F') pdf.line(10,85,200,85) pdf.cell(200,5,txt=" ",ln=1,align='F') pdf.set_font_size(20) pdf.set_font('courier',style='BI',size=20) pdf.cell(200,10,txt="List of Items",ln=1,align='C') pdf.set_font('courier',size=12) pdf.cell(200,5,txt='',ln=1) data = [['Product', 'Amount (in Kg.)', 'Price per Kg', 'Amount']] total=0 for i in range(len(item)): list1=[item[i],qty[i],unitprice[i],amt[i]] total+=float(amt[i]) data.append(list1) pdf.set_left_margin(20) col_width = pdf.w / 5 row_height = pdf.font_size+1 for row in data: for item1 in row: pdf.cell(col_width, row_height,txt=str(item1), border=1) pdf.ln(row_height*1) pdf.set_font(family='courier',style='B') pdf.cell(col_width*3,row_height,txt='Total',border=1,align='C') pdf.cell(col_width,row_height,txt=str(total),border=1) pdf.set_left_margin(140) pdf.cell(200,15,txt='',ln=1) pdf.set_font('courier',style='BI',size=15) pdf.cell(100,10,txt='Seal (Guru Sampoorna)',ln=1) InvoiceName="Invoice-"+Inid+".pdf"; pdf.output(InvoiceName)