def export_customer_tags(query): pdf = FPDF(orientation ='P', unit = 'mm', format='Letter') pdf.set_margins(left=4, top=8, right=5) pdf.set_auto_page_break(auto = True, margin = 10) pdf.add_page() pdf.set_font('Arial', '', 10) x_ref = pdf.get_x() width_tag = 69.6 count = 0 y_ref = pdf.get_y() count_tag = 0 for customer in query: if count_tag % 30 == 0 and count_tag > 0: pdf.add_page() #text = 'Prezado Alisson Barbosa\nRua das Orquídeas, 57\nJardim das Plantas\nCampina Grande - PB\n58415-000' text = '{}\n{}, {}\n{}\n{}\n{}'.format(customer.name, customer.street, customer.number, customer.neighborhood, customer.city, customer.cep) if count == 0: x_ref = pdf.get_x() y_ref = pdf.get_y() count += 1 elif count == 1: x_ref += width_tag count += 1 elif count == 2: x_ref += width_tag count = 0 pdf.set_xy(x = x_ref, y = y_ref) pdf.multi_cell(width_tag, 5.195, text, 0, 'L') count_tag += 1 response = HttpResponse(pdf.output(dest='S').encode('latin-1')) response['Content-Disposition'] = 'attachment;filename="Etiquetas.pdf"' return response
def generateDicePDF(): # save FPDF() class into # a variable pdf pdf = FPDF() pdf.add_page() pdf.add_font('Braille', '', 'static/Swell-Braille.ttf', uni=True) # set style and size of font # that you want in the pdf pdf.set_font("Arial", size=30) pdf.multi_cell(200, 5, txt='Braille Labels for Dice/Spinner\n\n', align='C') pdf.set_font("Arial", size=10) pdf.multi_cell( 200, 5, txt='Cut out Braille labels and paste them onto the dice/spinner.\n\n', align='C') index = 0 theText = ['0', '0'] f = open("static/userData/brailleForDice.txt", "r") # insert the texts in pdf theX = pdf.get_x() theY = pdf.get_y() for x in f: if theX >= 170: theX = 5 theY += 15 if theY >= 260: pdf.add_page() theY = 15 if index == 0: pdf.set_xy(theX - 5, theY) if index > 0: pdf.set_xy(theX + 17, theY) if index % 6 == 0: if int(theText[0]) > 9: theY += 15 theX = 5 pdf.set_xy(theX, theY) theX = pdf.get_x() theY = pdf.get_y() theText = x.split(':') pdf.set_font("Arial", size=8) pdf.multi_cell(15, 10, txt=theText[0], align='R') pdf.set_font('Braille', '', size=24) pdf.set_xy(theX + 15, theY) theX = pdf.get_x() theY = pdf.get_y() pdf.multi_cell(27, 10, txt=theText[1], align='L', border=1) index += 1 # save the pdf with name .pdf pdf.output("static/userData/theDiceSpinner.pdf")
def test_graphics_context(tmp_path): pdf = FPDF() pdf.add_page() pdf.set_font("helvetica", "", 12) pdf.set_text_color(0x00, 0xFF, 0x00) pdf.set_fill_color(0xFF, 0x88, 0xFF) pdf.set_y(20) pdf.cell(txt="outer 01", new_x=XPos.LMARGIN, new_y=YPos.NEXT, fill=True) with pdf.local_context(): pdf.set_font("courier", "BIU", 30) pdf.set_text_color(0xFF, 0x00, 0x00) pdf.set_fill_color(0xFF, 0xFF, 0x00) pdf.cell(txt="inner 01", new_x=XPos.LMARGIN, new_y=YPos.NEXT, fill=True) pdf.set_x(70) with pdf.rotation(30, pdf.get_x(), pdf.get_y()): pdf.set_fill_color(0x00, 0xFF, 0x00) pdf.cell(txt="inner 02", new_x=XPos.LMARGIN, new_y=YPos.NEXT, fill=True) pdf.set_stretching(150) pdf.cell(txt="inner 03", new_x=XPos.LMARGIN, new_y=YPos.NEXT, fill=True) pdf.cell(txt="outer 02", new_x=XPos.LMARGIN, new_y=YPos.NEXT, fill=True) assert_pdf_equal(pdf, HERE / "graphics_context.pdf", tmp_path)
def pokepdf(pokemon): # FPDF Object pdf = FPDF("L", "mm", "A5") # Add page pdf.add_page() # Paint the background pdf.set_fill_color(*color.get(pokemon["type"][0], (255, ))) pdf.rect(0, 0, 210, 297, "F") # Set font pdf.set_font(*fonts["title"]) pdf.set_xy(20, 10) # Add Pokeball ball = {False: "pokeball", True: "masterball"}[pokemon["legendary"]] pdf.image(f"images/balls/{ball}.png", pdf.get_x(), pdf.get_y() + 25, w=20) # Add Pokemon Name pdf.cell(w=0, txt=f"{pokemon['id']} - {pokemon['name']}".title(), align="C", ln=1) # Add Pokemon Sprite pdf.image(pokemon["sprite_url"], 80, pdf.get_y() + 10, w=50) # Set new font font = fonts["flavor"] pdf.set_font(*font) pdf.set_xy(10, 70) # Cut text if larger than page flavor = chunks(pokemon["flavor"], font) # Add flavor text for i in flavor: pdf.cell(w=0, h=5, txt=i, align="C", ln=2) # Add type symbols for i, typ in enumerate(pokemon["type"]): if len(pokemon["type"]) == 1: pos = [90] else: pos = [50, 120] pdf.image(f"images/types/{typ}.png", pos[i], pdf.get_y() + 15, w=40) # Export pdf path = f"output/{pokemon['id']}_{pokemon['name']}.pdf" pdf.output(path) print(f"pdf saved to {path}")
def createExercices(problems): exercises_per_column = 28 columns = 5 column_width = 50 cell_height = 7 number_width = 6 spacer = 2 pdf = FPDF(orientation="L") pdf.set_top_margin(5) pdf.set_auto_page_break(True, 1) pdf.add_page() pdf.set_font("Arial", size=12) start_x = pdf.get_x() start_y = pdf.get_y() for i in range(len(problems)): problem = problems[i] pdf.set_xy(start_x + int(i / exercises_per_column) * column_width, start_y + (i % exercises_per_column) * cell_height) border = "R" if (int(i / exercises_per_column) == columns - 1): border = 0 if (problem.unknown == UnknownElement.Z): pdf.cell(spacer, cell_height) pdf.cell(number_width, cell_height, txt=str(problem.x), align="C") pdf.cell(number_width, cell_height, txt=str(problem.operator), align="C") pdf.cell(number_width, cell_height, txt=str(problem.y), align="C") pdf.cell(number_width, cell_height, "=", align="C") pdf.cell(column_width - 4 * number_width - spacer, cell_height, border=border) elif (problem.unknown == UnknownElement.X): pdf.cell(column_width - 4 * number_width - spacer, cell_height) pdf.cell(number_width, cell_height, txt=str(problem.operator), align="C") pdf.cell(number_width, cell_height, txt=str(problem.y), align="C") pdf.cell(number_width, cell_height, "=", align="C") pdf.cell(number_width, cell_height, str(problem.z), align="C") pdf.cell(spacer, cell_height, border=border) pdf.output("simple_demo.pdf")
def pdf(list,length): desktop = os.path.join(os.path.join(os.environ['USERPROFILE']), 'Desktop') pdf = FPDF() pdf.set_margins(4,5, 2) pdf.add_page() pdf.set_font("Times",'B', size=30) pdf.cell(200, 10, txt="Test Paper", ln=15, align="C") pdf.ln(5) pdf.set_font('Times', 'B', 20) pdf.cell(200, 10, txt="Short Answers", ln=15, align="C") pdf.ln(8) pdf.set_font('Times', 'I', 10) pdf.multi_cell(200, 10, txt="This test has been generated using the Questionnaire software.No answers are provided to the questions and it is upto the discretion of the candidate to decide upon the right answers.A short answer is of 3-4 sentences,so the answers should be brief",align ='J') pdf.ln(10) pdf.set_font('Times', 'B', 15) for i in range(length): pdf.multi_cell(200, 10, txt=str(i+1) + "." + " " + list[i]) pdf.ln(10) x = pdf.get_x() y = pdf.get_y() pdf.dashed_line(x,y,x+175,y,6) pdf.ln(10) pdf.output(desktop + "/" + "Questions" + ".pdf")
def test_pdf_cell(self): pdf=FPDF() pdf.c_margin = 0.0 pdf.add_font('symbol','','font/DejaVuSans.ttf',uni=True) pdf.add_page() f = 0.81 font_name = 'times' text = 'small text' pdf.set_font(font_name,'',12) x,y = pdf.get_x(), pdf.get_y() w = pdf.get_string_width(text) h = pdf.font_size_pt / pdf.k pdf.cell(w, h, text) pdf.rect(x, y, w, h, '') pdf.line(x, y + f * h, x + w, y + f * h) text = 'Large text' pdf.set_font(font_name,'',24) x,y = pdf.get_x(), pdf.get_y() w = pdf.get_string_width(text) h = pdf.font_size_pt / pdf.k pdf.cell(w,h, text) pdf.rect(x, y, w, h, '') pdf.line(x, y + f * h, x + w, y + f * h) text = 'Larger text' pdf.set_font(font_name,'',48) x,y = pdf.get_x(), pdf.get_y() w = pdf.get_string_width(text) h = pdf.font_size_pt / pdf.k pdf.cell(w,h, text) pdf.rect(x, y, w, h, '') pdf.line(x, y + f * h, x + w, y + f * h) pdf.output('out/fpdf/test_pdf_cell.pdf', 'F')
def makePDF(cls, PDFName): pdf = FPDF('P', 'mm', (220, 110)) for supporter in cls.Supporters: print(supporter.preference) envelope = [1, 2, 3, 4, 6, 7, 8, 9] if supporter.preference in envelope: pdf.add_page() font_size = 20 line_spacing = 8 pdf.set_font('Arial', 'B', font_size) pdf.set_xy(20, 20) x_orig = pdf.get_x() y_orig = pdf.get_y() print(x_orig) print(y_orig) pdf.cell(40, 0, supporter.fullname) addrLines = supporter.address.split("\n") for i in range(0, len(addrLines)): print(addrLines[i]) pdf.set_xy(x_orig, y_orig + line_spacing * (i + 1)) pdf.set_font('Arial', 'B', font_size) pdf.cell(40, 0, addrLines[i]) pdf.image('logo.jpg', 120, 35, 60, 60) pdf.set_font('Arial', '', 6) stamptext = "" if supporter.preference in [3, 4, 8, 9]: stamptext = "Hand" elif supporter.preference in [1, 6]: stamptext = "UK" elif supporter.preference in [2, 7]: stamptext = "Int" pdf.set_xy(180, 12) pdf.cell(15, 20, stamptext, border=1, align='C') pdf.set_xy(180, 14) pdf.cell(15, 20, "{}T {}P {}F".format(supporter.letters[0], supporter.letters[1], supporter.letters[2]), border=0, align='C') pdf.output(PDFName, 'F')
def __row(self, pdf: FPDF, row: DayGroupedEntry): default_height = self.__pdf_height(pdf) splits = split_string(row[4], 90) height = default_height * len(splits) pdf.cell(pdf.w * 0.08, height, txt=row[0], border=1) pdf.cell(pdf.w * 0.07, height, txt=row[1].__str__(), border=1) pdf.cell(pdf.w * 0.07, height, txt=row[2].__str__(), border=1) pdf.cell(pdf.w * 0.06, height, txt=row[3].__str__(), border=1) desc_w = pdf.w * 0.57 if len(splits) > 1: current_x = pdf.get_x() current_y = pdf.get_y() pdf.multi_cell(desc_w, default_height, txt=row[4], border=1) pdf.set_xy(current_x + desc_w, current_y) else: pdf.cell(desc_w, height, txt=row[4], border=1) pdf.cell(pdf.w * 0.06, height, txt=row[5].__str__(), border=1) pdf.ln(height)
class PDFHandler(expand.Expand): def __init__(self, gui): super().__init__() self.gui = gui self.styles = {} self.terminselections = {} self.tourselections = {} self.touren = [] self.termine = [] self.url = None self.margins = None self.linespacing = None self.linkType = None self.ausgabedatei = None self.pdf = None global debug try: _ = os.environ["DEBUG"] debug = True except: debug = False # testing self.gui.pdfTemplateName = "C:/Users/Michael/PycharmProjects/ADFC1/venv/src/template152.json" self.pdfExtension = PDFExtension() self.md = markdown.Markdown(extensions=[self.pdfExtension]) if self.gui.pdfTemplateName is None or self.gui.pdfTemplateName == "": self.gui.pdfTemplate() if self.gui.pdfTemplateName is None or self.gui.pdfTemplateName == "": raise ValueError("must specify path to PDF template!") try: with open(self.gui.pdfTemplateName, "r", encoding="utf-8-sig") as jsonFile: self.pdfJS = json.load(jsonFile) except Exception as e: print( "Wenn Sie einen decoding-Fehler bekommen, öffnen Sie " + self.gui.pdfTemplateName + " mit notepad, dann 'Speichern unter' mit Codierung UTF-8") raise e self.parseTemplate() self.selFunctions = selektion.getSelFunctions() @staticmethod def nothingFound(): logger.info("Nichts gefunden") print("Nichts gefunden") def parseTemplate(self): for key in ["pagesettings", "fonts", "styles", "selection", "text"]: if self.pdfJS.get(key) is None: raise ValueError("pdf template " + self.gui.pdfTemplateName + " must have a section " + key) pagesettings = self.pdfJS.get("pagesettings") leftMargin = pagesettings.get("leftmargin") rightMargin = pagesettings.get("rightmargin") topMargin = pagesettings.get("topmargin") bottomMargin = pagesettings.get("bottommargin") self.margins = (leftMargin, topMargin, rightMargin) self.linespacing = pagesettings.get("linespacing") # float self.linkType = pagesettings.get("linktype") self.ausgabedatei = pagesettings.get("ausgabedatei") orientation = pagesettings.get("orientation")[0].upper() # P or L pformat = pagesettings.get("format") self.pdf = FPDF(orientation, "mm", pformat) self.pageWidth = FPDF.get_page_format(pformat, 1.0)[0] / (72.0 / 25.4) self.pdf.add_page() self.pdf.set_margins(left=leftMargin, top=topMargin, right=rightMargin) self.pdf.set_auto_page_break(True, margin=bottomMargin) self.pdfExtension.pdfTreeHandler.setDeps(self) self.pdf.add_font("arialuc", "", expand.pyinst("_builtin_fonts/arial.ttf"), True) self.pdf.add_font("arialuc", "B", expand.pyinst("_builtin_fonts/arialbd.ttf"), True) self.pdf.add_font("arialuc", "BI", expand.pyinst("_builtin_fonts/arialbi.ttf"), True) self.pdf.add_font("arialuc", "I", expand.pyinst("_builtin_fonts/ariali.ttf"), True) fonts = self.pdfJS.get("fonts") for font in iter(fonts): family = font.get("family") if family is None or family == "": raise ValueError("font family not specified") file = font.get("file") if file is None or file == "": raise ValueError("font file not specified") fontStyle = font.get("fontstyle") if fontStyle is None: fontStyle = "" unicode = font.get("unicode") if unicode is None: unicode = True self.pdf.add_font(family, fontStyle, file, unicode) styles = self.pdfJS.get("styles") for style in iter(styles): name = style.get("name") if name is None or name == "": raise ValueError("style name not specified") typ = style.get("type") if typ is None: typ = "text" font = style.get("font") if font is None and typ != "image": raise ValueError("style font not specified") fontstyle = style.get("style") if fontstyle is None: fontstyle = "" size = style.get("size") if size is None and typ != "image": raise ValueError("style size not specified") color = style.get("color") if color is None: color = "0,0,0" # black dimen = style.get("dimen") self.styles[name] = Style(name, typ, font, fontstyle, size, color, dimen) selection = self.pdfJS.get("selection") self.gliederung = selection.get("gliederung") if self.gliederung is None or self.gliederung == "": self.gliederung = self.gui.getGliederung() self.includeSub = selection.get("includesub") if self.includeSub is None: self.includeSub = self.gui.getIncludeSub() self.start = selection.get("start") if self.start is None or self.start == "": self.start = self.gui.getStart() self.end = selection.get("end") if self.end is None or self.end == "": self.end = self.gui.getEnd() sels = selection.get("terminselection") for sel in iter(sels): self.terminselections[sel.get("name")] = sel for key in sel.keys(): if key != "name" and not isinstance(sel[key], list): sel[key] = [sel[key]] sels = selection.get("tourselection") for sel in iter(sels): self.tourselections[sel.get("name")] = sel for key in sel.keys(): if key != "name" and not isinstance(sel[key], list): sel[key] = [sel[key]] def getIncludeSub(self): return self.includeSub def getEventType(self): if len(self.terminselections) != 0 and len(self.tourselections) != 0: return "Alles" if len(self.terminselections) != 0: return "Termin" if len(self.tourselections) != 0: return "Radtour" return self.gui.getEventType() def getRadTyp(self): rts = set() for sel in self.tourselections.values(): l = sel.get("radtyp") if l is None or len(l) == 0: l = [self.gui.getRadTyp()] for elem in l: rts.add(elem) if "Alles" in rts: return "Alles" if len(rts) == 1: return rts[0] return "Alles" def getUnitKeys(self): return self.gliederung def getStart(self): return self.start def getEnd(self): return self.end def handleTour(self, tour): self.touren.append(tour) def handleTermin(self, termin): self.termine.append(termin) def handleEnd(self): print("Template", self.gui.pdfTemplateName, "wird abgearbeitet") if self.linkType is None or self.linkType == "": self.linkType = self.gui.getLinkType() lines = self.pdfJS.get("text") lineCnt = len(lines) lineNo = 0 self.pdf.set_x(self.margins[0]) # left self.pdf.set_y(self.margins[1]) # top self.setStyle(self.styles.get("body")) self.pdf.cell(w=0, h=10, txt="", ln=1) while lineNo < lineCnt: line = lines[lineNo] if line.startswith("/comment"): lineNo += 1 continue if line.startswith("/template"): t1 = lineNo lineNo += 1 while not lines[lineNo].startswith("/endtemplate"): lineNo += 1 t2 = lineNo lineNo += 1 tempLines = lines[t1:t2] # /endtemplate not included self.evalTemplate(tempLines) else: self.evalLine(line, None) lineNo += 1 if self.ausgabedatei is None or self.ausgabedatei == "": self.ausgabedatei = self.gui.pdfTemplateName.rsplit(".", 1)[0] + "_" + self.linkType[0] + ".pdf" self.pdf.output(dest='F', name=self.ausgabedatei) print("Ausgabedatei", self.ausgabedatei, "wurde erzeugt") try: opath = os.path.abspath(self.ausgabedatei) os.startfile(opath) except Exception: logger.exception("opening " + self.ausgabedatei) def simpleNl(self): x = self.pdf.get_x() if x > self.margins[0]: self.pdf.ln() def extraNl(self): self.simpleNl() self.pdf.ln() def evalLine(self, line, event): if line.strip() == "": self.extraNl() return global debug if debug: print("line", line) text = [] self.align = "L" self.fontStyles = "" self.curStyle = self.styles.get("body") self.indentX = 0.0 words = line.split() l = len(words) last = l - 1 for i in range(l): word = words[i] if word.startswith("/"): cmd = word[1:] if cmd in self.styles.keys(): self.handleText("".join(text), event) text = [] self.curStyle = self.styles.get(cmd) elif cmd in ["right", "left", "center", "block"]: self.handleText("".join(text), event) text = [] self.align = cmd[0].upper() if self.align == 'B': self.align = 'J' # justification elif cmd in ["bold", "italic", "underline"]: self.handleText("".join(text), event) text = [] self.fontStyles += cmd[0].upper() else: if i < last: word = word + " " text.append(word) else: word = word.replace("\uaffe", "\n") if i < last: word = word + " " text.append(word) self.handleText("".join(text), event) self.simpleNl() def evalTemplate(self, lines): global debug if debug: print("template:") words = lines[0].split() typ = words[1] if typ != "/tour" and typ != "/termin": raise ValueError("second word after /template must be /tour or /termin") typ = typ[1:] sel = words[2] if not sel.startswith("/selection="): raise ValueError("third word after /template must start with /selection=") sel = sel[11:] sels = self.tourselections if typ == "tour" else self.terminselections if sel not in sels: raise ValueError("selection " + sel + " not in " + typ + "selections") sel = sels[sel] events = self.touren if typ == "tour" else self.termine self.evalEvents(sel, events, lines[1:]) def evalEvents(self, sel, events, lines): selectedEvents = [] for event in events: if selektion.selected(event, sel): selectedEvents.append(event) if len(selectedEvents) == 0: return lastEvent = selectedEvents[-1] for event in selectedEvents: for line in lines: if line.startswith("/comment"): continue self.evalLine(line, event) if event != lastEvent: # extra line between events, not after the last one self.evalLine("", None) def handleText(self, s: str, event): s = self.expand(s, event) if s is None or s == "": return # print("Text:", s) if self.curStyle.type == "image": self.drawImage(expand.pyinst(s)) return style = self.curStyle.copy() for fs in self.fontStyles: if style.fontStyle.find(fs) == -1: style.fontStyle += fs # self.fontStyles = "" self.setStyle(style) h = (style.size * 0.35278 + self.linespacing) if self.align == 'J': self.pdf.multi_cell(w=0, h=h, txt=s, border=0, align=self.align, fill=0) elif self.align == 'R': self.pdf.cell(w=0, h=h, txt=s, border=0, ln=0, align=self.align, fill=0, link=self.url) else: try: w = self.pdf.get_string_width(s) except Exception: w = 0 x = self.pdf.get_x() if (x + w) >= (self.pageWidth - self.margins[2]): # i.e. exceeds right margin self.multiline(h, s) else: self.pdf.cell(w=w, h=h, txt=s, border=0, ln=0, align=self.align, fill=0, link=self.url) # x = self.pdf.get_x() self.url = None def multiline(self, h: float, s: str): """ line too long, see if I can split line after blank """ x = self.pdf.get_x() l = len(s) # TODO limit l so that we do not search too long for a near enough blank while l > 0: w = self.pdf.get_string_width(s) if (x + w) < (self.pageWidth - 1 - self.margins[2]): self.pdf.cell(w=w, h=h, txt=s, border=0, ln=0, align=self.align, fill=0, link=self.url) # x = self.pdf.get_x() return nlx = s.find("\n", 0, l) lb = s.rfind(' ', 0, l) # last blank if 0 <= nlx < lb: lb = nlx + 1 if lb == -1: # can not split line if x > self.margins[0]: self.pdf.ln() if self.indentX > 0.0: self.pdf.set_x(self.indentX) x = self.pdf.get_x() l = len(s) continue else: # emergency, can not split line w = self.pdf.get_string_width(s) self.pdf.cell(w=w, h=h, txt=s, border=0, ln=1, align=self.align, fill=0, link=self.url) return sub = s[0:lb] w = self.pdf.get_string_width(sub) if (x + w) >= (self.pageWidth - 1 - self.margins[2]): l = lb continue self.pdf.cell(w=w, h=h, txt=sub, border=0, ln=0, align=self.align, fill=0, link=self.url) x = self.pdf.get_x() s = s[lb + 1:] w = self.pdf.get_string_width(s) if x > self.margins[0] and (x + w) >= (self.pageWidth - 1 - self.margins[2]): self.pdf.ln() if self.indentX > 0.0: self.pdf.set_x(self.indentX) x = self.pdf.get_x() l = len(s) def setStyle(self, style: Style): # print("Style:", style) self.pdf.set_font(style.font, style.fontStyle, style.size) rgb = style.color.split(',') self.pdf.set_text_color(int(rgb[0]), int(rgb[1]), int(rgb[2])) def drawImage(self, imgName: str): style = self.curStyle dimen = style.dimen # 60x40, wxh wh = dimen.split('x') w = int(wh[0]) h = int(wh[1]) x = self.pdf.get_x() y = self.pdf.get_y() if self.align == 'R': x = self.pageWidth - self.margins[2] - w - 10 y -= h # align lower edge of image with baseline of text (or so) if y < self.margins[1]: y = self.margins[1] self.pdf.image(imgName.strip(), x=x, y=y, w=w) # h=h self.pdf.set_y(self.pdf.get_y() + 7) def expBeschreibung(self, tour, _): desc = tour.getBeschreibung(True) # desc = codecs.decode(desc, encoding = "unicode_escape") self.md.convert(desc) self.md.reset() return None def expTourLeiter(self, tour, _): tl = tour.getPersonen() if len(tl) == 0: return self.evalLine("/bold Tourleiter: /block " + "\uaffe".join(tl), tour) def expAbfahrten(self, tour, _): afs = tour.getAbfahrten() if len(afs) == 0: return afl = [af[0] + " " + af[1] + " " + af[2] for af in afs] self.evalLine("/bold Ort" + ("" if len(afs) == 1 else "e") + ": /block " + "\uaffe".join(afl), tour) def expBetreuer(self, termin, _): tl = termin.getPersonen() if len(tl) == 0: return self.evalLine("/bold Betreuer: /block " + "\uaffe".join(tl), termin) def expZusatzInfo(self, tour, _): zi = tour.getZusatzInfo() if len(zi) == 0: return self.evalLine("/bold Zusatzinfo: /block " + "\uaffe".join(zi), tour) """
pdf.add_page() pdf.set_margins(20, 20, 10) # document title pdf.set_font("Times", "B", size=14) pdf.cell(0, 10, txt=title_1, align="C", ln=1) # document content pdf.set_font("Times", "I", size=12) pdf.cell(0, 7, txt=subtitle_1, ln=2) # bullet points of content pdf.set_font("Times", size=12) pdf.set_xy(70.00, 40.00) pdf.cell(0, 0, bullet_1, (pdf.get_x(), pdf.get_y()), ln=1) pdf.set_xy(70.00, 47.00) pdf.cell(0, 0, bullet_2, (pdf.get_x(), pdf.get_y()), ln=1) # pdf.set_xy(30.00, 52.00) # pdf.cell(0,0,bullet_3,(pdf.get_x(), pdf.get_y()), ln=1) # pdf.set_xy(30.00, 59.00) # pdf.cell(0,0,bullet_4,(pdf.get_x(), pdf.get_y()), ln=1) # introduction section pdf.set_font("Times", size=12) pdf.set_xy(20.00, 52.00) pdf.multi_cell(0, 7, text_1, (pdf.get_x(), pdf.get_y())) # boxplot description pdf.set_font("Times", "I", size=12) pdf.cell(200, 7, txt=subtitle_2, ln=2)
class PDFPrinter: PAGE_FORMAT = 'A4' UNIT = 'mm' MARGIN = 10 CONTENT_WIDTH = 297 - 2 * MARGIN CONTENT_HEIGHT = 210 - 2 * MARGIN HEADER_HEIGHT = 30 NOTES_HEIGHT = 17 TABLE_HEIGHT = CONTENT_HEIGHT - HEADER_HEIGHT - NOTES_HEIGHT FONT_S = 7 FONT_XS = 6.5 def __init__(self): self.colors = {} self.timelinesCount = None self.fontSize = 12 self.textColor = Color.WHITE self.pdf = FPDF(orientation='L', unit=PDFPrinter.UNIT, format=PDFPrinter.PAGE_FORMAT) self.pdf.add_font('regular', '', os.path.join('fonts', 'ubuntu', 'Ubuntu-B.ttf'), uni=True) self.pdf.add_font('condensed', '', os.path.join('fonts', 'roboto', 'RobotoCondensed-Regular.ttf'), uni=True) self.pdf.add_font('italic', '', os.path.join('fonts', 'roboto', 'RobotoCondensed-Bold.ttf'), uni=True) self.pdf.set_font("regular", size=self.fontSize) self.pdf.add_page() self.pdf.set_margins(PDFPrinter.MARGIN, PDFPrinter.MARGIN, PDFPrinter.MARGIN) self.uglyMeasure = FPDF(orientation='L', unit=PDFPrinter.UNIT, format=PDFPrinter.PAGE_FORMAT) self.uglyMeasure.add_font('regular', '', os.path.join('fonts', 'ubuntu', 'Ubuntu-B.ttf'), uni=True) self.uglyMeasure.add_font('condensed', '', os.path.join('fonts', 'roboto', 'RobotoCondensed-Regular.ttf'), uni=True) self.uglyMeasure.add_font('italic', '', os.path.join('fonts', 'roboto', 'RobotoCondensed-Bold.ttf'), uni=True) self.uglyMeasure.set_font("regular", size=self.fontSize) self.uglyMeasure.add_page() def defineColor(self, key, color): hex = color.lstrip('#') self.colors[key.lower()] = tuple( int(hex[i:i + 2], 16) for i in (0, 2, 4)) def printHeader(self, names): self.timelinesCount = len(names) boxWidth = PDFPrinter.CONTENT_WIDTH / self.timelinesCount boxPos = 0 for name in names: color = self.colors[name.lower()] x = PDFPrinter.MARGIN + boxWidth * boxPos y = PDFPrinter.MARGIN w = boxWidth h = 7 self._box(x, y, w, h, color=color, lineColor=Color.BLACK, lineWidth=0.1) self._text(x, y, w, h, text=name, color=self.textColor, font='regular', size=self.fontSize) boxPos += 1 def printTimetable(self, timetable): colCount = len(timetable.keys()) colWidth = PDFPrinter.CONTENT_WIDTH / colCount tablePositionY = 30 tableHeight = PDFPrinter.TABLE_HEIGHT + 1 tableHeaderHeight = 7 timelineRowHeight = tableHeight - tableHeaderHeight timelineRowPositionY = tablePositionY + tableHeaderHeight timeBlockWidth = (colWidth - 2) / self.timelinesCount timeWindow = self._findTimeWindow(timetable) yPerMin = (timelineRowHeight - 2) / (timeWindow["toTime"] - timeWindow["fromTime"]) colNo = 0 for key, schedules in timetable.items(): x = PDFPrinter.MARGIN + colWidth * colNo self._box(x=x, y=tablePositionY, w=colWidth, h=tableHeaderHeight, color=Color.LIGHT_GREY, lineColor=Color.BLACK, lineWidth=0.2) self._text(x=x, y=tablePositionY, w=colWidth, h=tableHeaderHeight, text=key, color=Color.BLACK, font='regular', size=self.fontSize) self._box(x=x, y=timelineRowPositionY, w=colWidth, h=timelineRowHeight, color=None, lineColor=Color.BLACK, lineWidth=0.2) self._drawTimeblocks(schedules, areaWidth=timeBlockWidth, areaPositionX=x, areaPositionY=timelineRowPositionY + 0.8, scaleY=yPerMin, timeWindowStart=timeWindow["fromTime"]) colNo += 1 def _drawTimeblocks(self, schedules, areaWidth, areaPositionX, areaPositionY, scaleY, timeWindowStart): timeBlockNo = 0 for person, timelines in schedules.items(): blockColor = self.colors[person.lower()] blockPositionX = areaPositionX + areaWidth * timeBlockNo + 0.5 * timeBlockNo + 0.5 for timeline in timelines: fromTimePosY = scaleY * (self._timeToInt(timeline.fromTime) - timeWindowStart) + 0.4 blockPositionY = areaPositionY + fromTimePosY blockHeight = scaleY * (self._timeToInt(timeline.toTime) - timeWindowStart) - fromTimePosY self._box(x=blockPositionX, y=blockPositionY, w=areaWidth, h=blockHeight, color=blockColor, lineColor=None) if (timeline.kind == "~"): self._drawLeftLines(x=blockPositionX, y=blockPositionY, w=areaWidth, h=blockHeight) elif (timeline.kind == "d"): self._drawTwoRightLines(x=blockPositionX, y=blockPositionY, w=areaWidth, h=blockHeight) elif (timeline.kind == "e"): self._drawEmptyRightCorner(x=blockPositionX, y=blockPositionY, w=areaWidth, h=blockHeight) self._drawTimeblockLabels(areaX=blockPositionX, areaY=blockPositionY, areaW=areaWidth, areaH=blockHeight, timeline=timeline, backColor=blockColor) timeBlockNo += 1 def _drawLeftLines(self, x, y, w, h): hw = h / w posX = x posXM = x + w posY = y posYM = y + h jump = 3 while (posXM > x): posX += jump posXM -= jump posY += jump * hw posYM -= jump * hw if jump == 2: jump = 0.5 else: jump = 2 if (posX < x + w and posY < y + h): self._line(posX, y, x, posY, Color.WHITE, lineWidth=0.2) if (posXM > x and posYM > y): self._line(posXM, y + h, x + w, posYM, Color.WHITE, lineWidth=0.2) def _drawTwoRightLines(self, x, y, w, h): hw = h / w posX = x posXM = x + w posY = y posYM = y + h jump = 2 for _ in range(4): posX += jump posXM -= jump posY += jump * hw posYM -= jump * hw # if jump == 2: # jump = 0.7 # else: # jump = 2 if (posX < x + w and posY < y + h): self._line(posX, y + h, x, posYM, Color.WHITE, lineWidth=0.3) if (posXM > x and posYM > y): self._line(posXM, y, x + w, posY, Color.WHITE, lineWidth=0.3) def _drawEmptyRightCorner(self, x, y, w, h): hw = h / w posX = x posXM = x + w posY = y posYM = y + h jump = 1 for p in range(9): posX += jump posXM -= jump posY += jump * hw posYM -= jump * hw if p > 5: jump = 1 else: jump = 0.2 if (posX < x + w and posY < y + h): self._line(posX, y + h, x, posYM, Color.WHITE, lineWidth=0.2) if (posXM > x and posYM > y): self._line(posXM, y, x + w, posY, Color.WHITE, lineWidth=0.2) def _drawTimeblockLabels(self, areaX, areaY, areaW, areaH, timeline, backColor): label = [] if (timeline.name): label.append(timeline.name.upper()) for component in timeline.components: label.append(component.upper()) if (label): self._textBlock(x=areaX, y=areaY, w=areaW, h=areaH, textLines=label, color=Color.WHITE, font='condensed', size=PDFPrinter.FONT_XS, align='C', backColor=backColor) if (timeline.fromTime): textSize = self._measure(text=timeline.fromTime, font='italic', size=PDFPrinter.FONT_S) self._text(x=areaX, y=areaY - 1, w=areaW / 2, h=textSize.y, text=timeline.fromTime, color=Color.WHITE, font='italic', size=PDFPrinter.FONT_S, align='L', backColor=backColor) if (timeline.toTime): textSize = self._measure(text=timeline.toTime, font='italic', size=PDFPrinter.FONT_S) self._text(x=areaX + areaW / 2, y=areaY + areaH - textSize.y + 1, w=areaW / 2, h=textSize.y, text=timeline.toTime, color=Color.WHITE, font='italic', size=PDFPrinter.FONT_S, align='R', backColor=backColor) def printNotes(self, notes): x = PDFPrinter.MARGIN y = PDFPrinter.MARGIN + PDFPrinter.HEADER_HEIGHT + PDFPrinter.TABLE_HEIGHT w = PDFPrinter.CONTENT_WIDTH h = 5 for note in notes: y += h self._text(x, y, w, 0, text=note, color=Color.BLACK, font='regular', size=self.fontSize, align='L') def save(self, fileName): self.pdf.output(fileName) def _measure(self, text, font, size): self.uglyMeasure.set_font(font, size=size) self.uglyMeasure.set_xy(0, 0) self.uglyMeasure.write(size / 2.83, txt=text) sizeX = self.uglyMeasure.get_x() self.uglyMeasure.write(size / 2.83, txt="\n") sizeY = self.uglyMeasure.get_y() result = Size(sizeX, sizeY) return result def _text(self, x, y, w, h, text, color, font, size, align='C', backColor=None): self.pdf.set_text_color(color[0], color[1], color[2]) self.pdf.set_font(font, size=size) self.pdf.set_xy(x, y) fillBackground = False if (backColor): self.pdf.set_fill_color(backColor[0], backColor[1], backColor[2]) fillBackground = True self.pdf.cell(w, h, txt=text, ln=1, align=align, fill=fillBackground) def _textBlock(self, x, y, w, h, textLines, color, font, size, align='C', backColor=None): textH = 0 texts = [] for line in textLines: textSize = self._measure(text=line, font=font, size=size) textSize.y += 1 textH += textSize.y texts.append({"txt": line, "height": textSize.y}) self.pdf.set_text_color(color[0], color[1], color[2]) self.pdf.set_font(font, size=size) posY = y + (h - textH) / 2 fillBackground = False if (backColor): self.pdf.set_fill_color(backColor[0], backColor[1], backColor[2]) fillBackground = True for line in texts: self.pdf.set_xy(x, posY) self.pdf.cell(w, line["height"], txt=line["txt"], align=align, fill=fillBackground) posY += line["height"] def _box(self, x, y, w, h, color, lineColor, lineWidth=0): style = '' if (lineColor): self.pdf.set_line_width(lineWidth) self.pdf.set_draw_color(lineColor[0], lineColor[1], lineColor[2]) style += 'D' if (color): self.pdf.set_fill_color(color[0], color[1], color[2]) style += 'F' self.pdf.rect(x, y, w, h, style) def _line(self, x1, y1, x2, y2, color, lineWidth): self.pdf.set_line_width(lineWidth) self.pdf.set_draw_color(color[0], color[1], color[2]) self.pdf.line(x1, y1, x2, y2) def _findTimeWindow(self, timetable): minTime = self._timeToInt("24:00") maxTime = self._timeToInt("00:00") for daySchedule in timetable.values(): for personalSchedule in daySchedule.values(): for schedule in personalSchedule: f = self._timeToInt(schedule.fromTime) t = self._timeToInt(schedule.toTime) minTime = min(minTime, f, t) maxTime = max(maxTime, f, t) return {"fromTime": minTime, "toTime": maxTime} def _timeToInt(self, str): parts = str.split(':') return int(parts[0]) * 60 + int(parts[1])
# for first table pdf.set_font('Times', '', 12) pdf.set_draw_color(128, 128, 128) th = pdf.font_size for row in test_case_related_info: # print(ybefore, '---', xbefore) for datum in row: # Enter data in columns # Notice the use of the function str to coerce any input to the # string type. This is needed # since pyFPDF expects a string, not a number. # pdf.cell(col_width, 1.5 * th, str(row), border=1) ybefore = pdf.get_y() xbefore = pdf.get_x() pdf.multi_cell(test_col_width, 2 * th, str(datum), align='C', border=0, fill=1) pdf.set_xy(test_col_width + xbefore, ybefore) pdf.ln(2 * th) pdf.ln(25) # feature case heading pdf.set_font('Times', '', 12) pdf.cell(0, 7, 'Feature Related Info-', 1, 1, 'L', fill=1) pdf.ln(5)
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())
class Report: def __init__(self, data): self.output_path = os.path.join(data.data_path, "stats") self.dataset_name = os.path.basename(data.data_path) self.mapi_light_light_green = [210, 245, 226] self.mapi_light_green = [5, 203, 99] self.mapi_light_grey = [218, 222, 228] self.mapi_dark_grey = [99, 115, 129] 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.stats = self._read_stats_file("stats.json") def save_report(self, filename): self.pdf.output(os.path.join(self.output_path, filename), "F") def _make_table(self, columns_names, rows, row_header=False): 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): file_path = os.path.join(self.output_path, filename) with io.open_rt(file_path) as fin: return io.json_load(fin) def _make_section(self, title): 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): 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, desired_height): width, height = PIL.Image.open(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( 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): # 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, "OpenSfM Quality Report", align="C") self.pdf.set_xy(self.margin, self.title_size) # version number try: out, _ = subprocess.Popen( ["git", "describe", "--tags"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, ).communicate() version = out.strip().decode() except BaseException as e: logger.warning( f"Exception thrwon while extracting 'git' version, {e}") version = "" # indicate we don't know the version version = "unknown" if version == "" else version 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 OpenSfM version {version}", align="R") self.pdf.set_xy(self.margin, self.pdf.get_y() + 2 * self.margin) def make_dataset_summary(self): 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", f"{self.stats['processing_statistics']['steps_times']['Total Time']:.2f} seconds", ], ] self._make_table(None, rows, True) self.pdf.set_xy(self.margin, self.pdf.get_y() + self.margin) def _has_meaningful_gcp(self): return (self.stats["reconstruction_statistics"]["has_gcp"] and "average_error" in self.stats["gcp_errors"]) def make_processing_summary(self): 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") rows = [ [ "Reconstructed Images", f"{rec_shots} over {init_shots} shots ({rec_shots/init_shots*100:.1f}%)", ], [ "Reconstructed Points", 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)], ] 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 = 130 topview_grids = [ f for f in os.listdir(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): 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_gps_details(self): self._make_section("GPS/GCP Errors Details") # GPS for error_type in ["gps", "gcp"]: 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) self.pdf.set_xy(self.margin, self.pdf.get_y() + self.margin / 2) def make_features_details(self): self._make_section("Features Details") heatmap_height = 60 heatmaps = [ f for f in os.listdir(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): self._make_section("Reconstruction Details") rows = [ [ "Average reprojection Error", f"{self.stats['reconstruction_statistics']['reprojection_error']:.2f} pixels", ], [ "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) def make_camera_models_details(self): self._make_section("Camera Models Details") for camera, params in self.stats["camera_errors"].items(): residual_grids = [ f for f in os.listdir(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 = 80 self._make_centered_image( os.path.join(self.output_path, residual_grids[0]), residual_grid_height) def make_tracks_details(self): self._make_section("Tracks Details") matchgraph_height = 60 matchgraph = [ f for f in os.listdir(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): self.pdf.add_page("P") def generate_report(self): self.make_title() self.make_dataset_summary() self.make_processing_summary() self.add_page_break() self.make_features_details() self.make_reconstruction_details() self.make_tracks_details() self.add_page_break() self.make_camera_models_details() self.make_gps_details() self.make_processing_time_details()
def createPDFacordo(db: Session, vaga: PessoaProjeto): contratado = get_pessoa_by_id(db, vaga.pessoa_id) projeto = get_projeto(db, vaga.projeto_id) contratante = get_pessoa_by_id(db, projeto.pessoa_id) acordo = get_tipo_acordo_by_id(db, vaga.tipo_acordo_id) # Observar após refatoração if (vaga.papel_id == 1): papel = "aliado" elif (vaga.papel_id == 2): papel = "colaborador" elif (vaga.papel_id == 3): papel = "idealizador" pdf = FPDF() pdf.add_page(orientation='P') espacamento = 8 pdf.set_margins(20, 20, 20) pdf.set_font("Arial", 'B', size=16) # Espaço de formatação pdf.cell(20, 20, txt='', ln=1) pdf.cell(175, 12, txt='ACORDO DE PRESTAÇÃO DE SERVIÇOS', ln=1, align="C") pdf.set_font("Arial", 'B', size=14) pdf.cell(175, 12, txt='IDENTIFICAÇÃO DAS PARTES CONTRATANTES', ln=1, align="L") # Corpo pdf.set_font("Arial", 'B', size=12) pdf.cell(pdf.get_string_width('CONTRATANTE: '), espacamento, txt='CONTRATANTE: ', align="L") pdf.set_font("Arial", size=12) w = pdf.get_x() pdf.cell(w, espacamento, txt=contratante.nome, ln=1, align="L") pdf.set_font("Arial", 'B', size=12) pdf.cell(pdf.get_string_width('CONTRATADO: '), espacamento, txt='CONTRATADO: ', align="L") pdf.set_font("Arial", size=12) w = pdf.get_x() pdf.cell(w, espacamento, txt=contratado.nome, ln=1, align="L") pdf.cell(20, 5, txt='', ln=1) pdf.multi_cell( 0, espacamento, txt= 'As partes acima identificadas têm, entre si, justo e acertado o presente Acordo de Prestação de Serviços, que se regerá pelo objeto do acordo pelas condições de remuneração, forma e termo de pagamento descritas no presente.', align="J") pdf.set_font("Arial", 'B', size=14) pdf.cell(175, 15, txt='DO OBJETO DE ACORDO', ln=1, align="L") pdf.set_font("Arial", size=12) pdf.multi_cell( 0, espacamento, txt='É objeto do presente acordo a prestação do serviço no projeto ' + projeto.nome + ' como ' + papel + ' na vaga de ' + vaga.titulo + ' por meio de um contrato como ' + acordo.descricao + '.', align="J") if (vaga.remunerado): pdf.multi_cell( 0, espacamento, txt= 'Esta prestação de serviços será remunerada com valores e pagamentos a serem negociados entre ambas as partes.', align="J") else: pdf.multi_cell( 0, espacamento, txt= 'Esta prestação de serviços não será remunerada conforme anunciado na plataforma Conectar.', align="J") pdf.cell(20, 10, txt='', ln=1) pdf.multi_cell( 0, espacamento, txt= 'A execução da prestação de serviço aqui acordada será de responsabilidade das partes envolvidas, eximindo da plataforma Conectar de qualquer obrigação com o contratante ou contratado.', align="J") hoje = datetime.now() data_str = 'Dois Vizinhos, ' + \ str(hoje.day) + " de " + MESES[hoje.month] + " de " + str(hoje.year) pdf.cell(20, 7, txt='', ln=1) pdf.cell(200, espacamento, txt=data_str, ln=1, align="L") pdf.cell(20, 20, txt='', ln=1) pdf.cell(175, espacamento, txt='___________________ ___________________', ln=1, align="C") pdf.cell(175, espacamento, txt='Contratante Contratado', ln=1, align="C") saida = str(uuid.uuid4().hex) + ".pdf" pdf.output(PDF_PATH + saida) if not os.getenv("DEV_ENV"): upload_object(PDF_PATH + saida, 'conectar') os.remove(PDF_PATH + saida) return saida
def create_report(patient_name, interp_date, study_date, patient_code, interp_dr, sex, dob, height, weight, bmi, recording_time, monitoring_time, ahi, odi, mean_spo2, min_spo2, mean_heart_rate, diagnosis, recommendations, age, lights_off_time, lights_on_time, bed_time, oai, cai): pdf = FPDF() pdf.set_left_margin(margin=25) pdf.set_right_margin(margin=25) # First Page pdf.add_page() pdf.image('resources/logo.png', x=(WIDTH-150)/2, y=2, w=150, type='PNG') pdf.ln(20) pdf.set_font(family='Arial', style='B', size=10) pdf.multi_cell( w=0, h=4, txt='1060 S. Main St., Suite 301A\nSt. George, UT 84770\n(855) 276-3263', align='C') pdf.ln(5) pdf.set_font(family='Arial', style='', size=10) pdf.cell(w=0, h=4, txt='HOME SLEEP TEST ANALYSIS REPORT', align='L', ln=1) pdf.ln(5) pdf.cell(w=(REMAINING_WIDTH)/2, h=4, txt=f'Patient Name: {patient_name}', align='L') pdf.cell(w=(REMAINING_WIDTH)/2, h=4, txt=f'Sex: {sex}', align='L', ln=1) pdf.cell(w=(REMAINING_WIDTH)/2, h=4, txt=f'Interp. Date: {interp_date}', align='L') pdf.cell(w=(REMAINING_WIDTH)/2, h=4, txt=f'DOB: {dob}', align='L', ln=1) pdf.cell(w=(REMAINING_WIDTH)/2, h=4, txt=f'Study Date: {study_date}', align='L') pdf.cell(w=(REMAINING_WIDTH)/2, h=4, txt=f'Height: {height} in.', align='L', ln=1) pdf.cell(w=(REMAINING_WIDTH)/2, h=4, txt=f'Patient Code: {patient_code}', align='L') pdf.cell(w=(REMAINING_WIDTH)/2, h=4, txt=f'Weight: {weight} lbs.', align='L', ln=1) pdf.cell(w=(REMAINING_WIDTH)/2, h=4, txt=f'Interp Physician: {interp_dr}', align='L') pdf.cell(w=(REMAINING_WIDTH)/2, h=4, txt=f'BMI: {bmi}', align='L', ln=1) pdf.ln(5) pdf.set_font(family='Arial', style='', size=9) pdf.multi_cell( w=0, h=4, txt='Test Sibel underwent a home sleep diagnostic study on 8/26/2019 investigating the possibility of obstructive sleep apnea. The study was conducted utilizing the Respironics Alice NightOne device. Raw data from the NightOne study was reviewed.') pdf.ln(5) pdf.cell(w=0, h=4, txt='Summary of Findings:', align='L', ln=1) pdf.ln(2) pdf.set_font(family='Arial', style='', size=10) pdf.cell(w=(REMAINING_WIDTH)/2, h=4, txt=f'Study Date: {study_date}', align='L') pdf.cell(w=(REMAINING_WIDTH)/2, h=4, txt=f'ODI: {odi}', align='L', ln=1) pdf.cell(w=(REMAINING_WIDTH)/2, h=4, txt=f'Recording Time (min): {recording_time}', align='L') pdf.cell(w=(REMAINING_WIDTH)/2, h=4, txt=f'Mean Sp02 Sat: {mean_spo2}%', align='L', ln=1) pdf.cell(w=(REMAINING_WIDTH)/2, h=4, txt=f'Monitoring Time (min): {monitoring_time}', align='L') pdf.cell(w=(REMAINING_WIDTH)/2, h=4, txt=f'Min. Sp02 Desat: {min_spo2}%', align='L', ln=1) pdf.cell(w=(REMAINING_WIDTH)/2, h=4, txt=f'AHI: {ahi}', align='L') pdf.cell(w=(REMAINING_WIDTH)/2, h=4, txt=f'Mean Heart Rate: {mean_heart_rate}', align='L', ln=1) pdf.ln(3) pdf.set_font(family='Arial', style='', size=9) pdf.multi_cell( w=0, h=4, txt='AHI=Apneas + Hypopneas per hour of sleep. All apneas and hypopneas must be at least 10 seconds in duration and have a minimum of 4% associated desaturation. AHI calculated using Remmers Respiratory Disturbance Index.ODI=Oxygen desaturation of at least 4% from baseline per hour of sleep') pdf.ln(5) pdf.cell(w=18, h=4, txt='Diagnosis: ', align='L') pdf.set_font(family='Arial', style='B', size=10) pdf.cell(w=(REMAINING_WIDTH-18), h=4, txt=f'{diagnosis}', align='L', ln=1) pdf.ln(5) pdf.set_font(family='Arial', style='', size=9) pdf.cell(w=0, h=4, txt='Recommendations: ', align='L') pdf.ln(4) for i in recommendations: pdf.cell(w=8, h=4, txt=' -', align='L') pdf.multi_cell(w=(REMAINING_WIDTH-18), h=4, txt=i.recommendation_data) for j in i.sub_list: pdf.cell(w=8, h=4, align='L') pdf.cell(w=8, h=4, txt=' -', align='L') pdf.multi_cell(w=(REMAINING_WIDTH-18), h=4, txt=j) pdf.ln(2) pdf.ln(2) pdf.multi_cell( w=0, h=4, txt='Clinical follow-up as deemed necessary would be appropriate. Patient should be advised on the long term consequences of OSA if left untreated, need for treatment, and close follow up. Retesting or follow up is recommended to ensure the apnea is controlled and the symptoms are relieved on the chosen therapy. ') pdf.ln(5) pdf.multi_cell( w=0, h=4, txt='Untreated obstructive sleep apnea is associated with hypertension, heart disease, stroke, daytime sleepiness, cognitive dysfunction, mood disorders and sudden death.') pdf.ln(5) pdf.ln(SIGN_LOCATION_Y-pdf.get_y()) pdf.cell(w=50, h=4, txt="Sincerely,", align='L') pdf.image('resources/sign.png', x=20, y=SIGN_LOCATION_Y+5, w=60, type='PNG') pdf.ln(20) pdf.multi_cell( w=0, h=4, txt=f'Dr.{interp_dr}\nDiplomate ABIM-Sleep Medicine\nElectronically Signed') # Second Page pdf.add_page() pdf.image('resources/philips-logo.png', x=LEFT_MARGIN, y=10, w=60, type='PNG') pdf.ln(15) pdf.set_font(family='Arial', style='B', size=20) pdf.cell(w=60, h=4) pdf.cell(w=120, h=10, txt='Sleep Test Report', align='C', ln=1) pdf.ln(5) pdf.set_font(family='Arial', style='B', size=10) # Table Header pdf.set_draw_color(r=0, g=102, b=204) pdf.set_fill_color(r=213, g=227, b=187) pdf.cell(w=100, h=7, align='L', border=1, fill=True) pdf.cell(w=REMAINING_WIDTH-100, h=7, txt=f'Study Date: {study_date}', align='L', border=1, fill=True, ln=1) pdf.set_font(family='Arial', style='B', size=10) # Row 1 pdf.cell(w=20, h=5, txt='Patient', align='L', border=1) pdf.set_font(family='Arial', style='', size=10) pdf.cell(w=60, h=5, txt=f'{patient_name}', align='L', border=1) pdf.set_font(family='Arial', style='B', size=10) pdf.cell(w=20, h=5, txt='Recording', align='L', border=1) pdf.set_font(family='Arial', style='', size=10) pdf.cell(w=60, h=5, txt='Alice NightOne', align='L', border=1, ln=1) pdf.set_font(family='Arial', style='B', size=10) # Row 2 pdf.cell(w=20, h=5, txt='Sex', align='L', border=1) pdf.set_font(family='Arial', style='', size=10) pdf.cell(w=60, h=5, txt=f'{sex}', align='L', border=1) pdf.set_font(family='Arial', style='B', size=10) pdf.cell(w=20, h=5, txt='Height', align='L', border=1) pdf.set_font(family='Arial', style='', size=10) pdf.cell(w=60, h=5, txt=f'{height} in.', align='L', border=1, ln=1) pdf.set_font(family='Arial', style='B', size=10) # Row 3 pdf.cell(w=20, h=5, txt='DOB', align='L', border=1) pdf.set_font(family='Arial', style='', size=10) pdf.cell(w=60, h=5, txt=f'{dob}', align='L', border=1) pdf.set_font(family='Arial', style='B', size=10) pdf.cell(w=20, h=5, txt='Weight', align='L', border=1) pdf.set_font(family='Arial', style='', size=10) pdf.cell(w=60, h=5, txt=f'{weight} lbs.', align='L', border=1, ln=1) pdf.set_font(family='Arial', style='B', size=10) # Row 4 pdf.cell(w=20, h=5, txt='Age', align='L', border=1) pdf.set_font(family='Arial', style='', size=10) pdf.cell(w=60, h=5, txt=f'{age} years', align='L', border=1) pdf.set_font(family='Arial', style='B', size=10) pdf.cell(w=20, h=5, txt='BMI', align='L', border=1) pdf.set_font(family='Arial', style='', size=10) pdf.cell(w=60, h=5, txt=f'{bmi}', align='L', border=1, ln=1) pdf.ln(5) pdf.set_font(family='Arial', style='B', size=10) # Table-2 Header pdf.cell(w=REMAINING_WIDTH, h=7, txt='Times and Durations', align='L', border=1, fill=True, ln=1) pdf.set_font(family='Arial', style='B', size=10) # Row 1 pdf.cell(w=40, h=5, txt='Lights off clock time', align='L', border=1) pdf.set_font(family='Arial', style='', size=10) pdf.cell(w=40, h=5, txt=f'{lights_off_time}', align='L', border=1) pdf.set_font(family='Arial', style='B', size=10) pdf.cell(w=40, h=5, txt='Total Time Recording', align='L', border=1) pdf.set_font(family='Arial', style='', size=10) pdf.cell(w=40, h=5, txt=f'{recording_time} minutes', align='L', border=1, ln=1) pdf.set_font(family='Arial', style='B', size=10) # Row 2 pdf.cell(w=40, h=5, txt='Lights on clock time', align='L', border=1) pdf.set_font(family='Arial', style='', size=10) pdf.cell(w=40, h=5, txt=f'{lights_on_time}', align='L', border=1) pdf.set_font(family='Arial', style='B', size=10) pdf.cell(w=40, h=5, txt='Time In Bed', align='L', border=1) pdf.set_font(family='Arial', style='', size=10) pdf.cell(w=40, h=5, txt=f'{bed_time} minutes', align='L', border=1, ln=1) pdf.set_font(family='Arial', style='B', size=10) # Row 3 pdf.cell(w=40, h=5, txt='', align='L', border=1) pdf.set_font(family='Arial', style='', size=10) pdf.cell(w=40, h=5, txt='', align='L', border=1) pdf.set_font(family='Arial', style='B', size=10) pdf.cell(w=40, h=5, txt='Monitoring Time', align='L', border=1) pdf.set_font(family='Arial', style='', size=10) pdf.cell(w=40, h=5, txt=f'{monitoring_time} minutes', align='L', border=1, ln=1) pdf.ln(5) pdf.set_font(family='Arial', style='B', size=10) # Table-3 Header pdf.cell(w=REMAINING_WIDTH, h=7, txt='Device and Sensor Details', align='L', border=1, fill=True, ln=1) pdf.set_font(family='Arial', style='', size=10) # Row 1 pdf.multi_cell( w=REMAINING_WIDTH, h=4, txt='The study was recorded on a Philips Respironics Alice NightOne device using 1 RIP effort belt and a pressure based flow sensor. The heart rate is derived from the oximeter sensor and the snore signal is derived from the pressure sensor. The device also records body position and uses it to determine the monitoring time(sleep/wake periods).', align='', border=1) pdf.ln(5) pdf.set_font(family='Arial', style='B', size=10) # Table-4 Header pdf.cell(w=REMAINING_WIDTH, h=7, txt='Summary', align='L', border=1, fill=True, ln=1) pdf.set_fill_color(r=250, g=191, b=143) pdf.cell(w=20, h=6, txt='AHI', align='C', border=1) # Row 1 pdf.cell(w=20, h=6, txt=f'{ahi}', align='C', border=1, fill=True) pdf.cell(w=20, h=6, txt='OAI', align='C', border=1) pdf.cell(w=20, h=6, txt=f'{oai}', align='C', border=1, fill=True) pdf.cell(w=20, h=6, txt='CAI', align='C', border=1) pdf.cell(w=20, h=6, txt=f'{cai}', align='C', border=1, fill=True) pdf.cell(w=20, h=6, txt='Min Desat', align='C', border=1) pdf.cell(w=20, h=6, txt=f'{min_spo2}', align='C', border=1, fill=True, ln=1) pdf.set_font(family='Arial', style='', size=8.5) pdf.set_text_color(r=107, g=107, b=107) pdf.multi_cell( w=REMAINING_WIDTH, h=4, txt='AHI is the number of respiratory events per hour. OAI is the number of obstructive apneas per hour. CAI is the number of central apneas per hour. Lowest Desat is the lowest blood oxygen level that lasted at least 2 seconds.', align='', ) pdf.ln(5) pdf.set_text_color(r=0, g=0, b=0) # Table 5 - Header pdf.set_fill_color(r=213, g=227, b=187) pdf.set_font(family='Arial', style='B', size=10) pdf.cell(w=REMAINING_WIDTH, h=7, txt='Respiratory Events', align='L', border=1, fill=True, ln=1) temp_y = pdf.get_y() pdf.set_font(family='Arial', style='B', size=8) # Row 1 pdf.cell(w=30, h=12, txt='', align='C', border=1) temp_x = pdf.get_x() pdf.multi_cell(w=15, h=6, txt='Index (#/hour)', align='C', border=1) pdf.set_y(temp_y) pdf.set_x(temp_x+15) temp_x = pdf.get_x() pdf.multi_cell(w=15, h=6, txt='Total # of Events', align='C', border=1) pdf.set_y(temp_y) pdf.set_x(temp_x+15) temp_x = pdf.get_x() pdf.multi_cell(w=15, h=6, txt='Mean Duration', align='C', border=1) pdf.set_y(temp_y) pdf.set_x(temp_x+15) temp_x = pdf.get_x() pdf.multi_cell(w=15, h=6, txt='Max Duration', align='C', border=1) pdf.set_y(temp_y) pdf.set_x(temp_x+15) pdf.cell(w=70, h=4, txt='# of Events by Position', align='C', border=1, ln=1) pdf.set_y(temp_y+4) pdf.set_x(temp_x+15) pdf.cell(w=14, h=8, txt='Supine', align='C', border=1) pdf.cell(w=14, h=8, txt='Prone', align='C', border=1) pdf.cell(w=14, h=8, txt='Left', align='C', border=1) pdf.cell(w=14, h=8, txt='Right', align='C', border=1) pdf.cell(w=14, h=8, txt='Up', align='C', border=1, ln=1) pdf.set_font(family='Arial', style='B', size=8) # Row 2 pdf.cell(w=30, h=6, txt='Central Apneas', align='L', border=1) pdf.set_font(family='Arial', style='', size=8) pdf.cell(w=15, h=6, txt='4.3', align='C', border=1) pdf.cell(w=15, h=6, txt='29', align='C', border=1) pdf.cell(w=15, h=6, txt='21.7', align='C', border=1) pdf.cell(w=15, h=6, txt='127', align='C', border=1) pdf.cell(w=14, h=6, txt='1', align='C', border=1) pdf.cell(w=14, h=6, txt='3', align='C', border=1) pdf.cell(w=14, h=6, txt='2', align='C', border=1) pdf.cell(w=14, h=6, txt='23', align='C', border=1) pdf.cell(w=14, h=6, txt='0', align='C', border=1, ln=1) pdf.set_font(family='Arial', style='B', size=8) # Row 3 pdf.cell(w=30, h=6, txt='Constructive Apneas', align='L', border=1) pdf.set_font(family='Arial', style='', size=8) pdf.cell(w=15, h=6, txt='4.3', align='C', border=1) pdf.cell(w=15, h=6, txt='29', align='C', border=1) pdf.cell(w=15, h=6, txt='21.7', align='C', border=1) pdf.cell(w=15, h=6, txt='127', align='C', border=1) pdf.cell(w=14, h=6, txt='1', align='C', border=1) pdf.cell(w=14, h=6, txt='3', align='C', border=1) pdf.cell(w=14, h=6, txt='2', align='C', border=1) pdf.cell(w=14, h=6, txt='23', align='C', border=1) pdf.cell(w=14, h=6, txt='0', align='C', border=1, ln=1) pdf.set_font(family='Arial', style='B', size=8) # Row 4 pdf.cell(w=30, h=6, txt='Mixed Apneas', align='L', border=1) pdf.set_font(family='Arial', style='', size=8) pdf.cell(w=15, h=6, txt='4.3', align='C', border=1) pdf.cell(w=15, h=6, txt='29', align='C', border=1) pdf.cell(w=15, h=6, txt='21.7', align='C', border=1) pdf.cell(w=15, h=6, txt='127', align='C', border=1) pdf.cell(w=14, h=6, txt='1', align='C', border=1) pdf.cell(w=14, h=6, txt='3', align='C', border=1) pdf.cell(w=14, h=6, txt='2', align='C', border=1) pdf.cell(w=14, h=6, txt='23', align='C', border=1) pdf.cell(w=14, h=6, txt='0', align='C', border=1, ln=1) pdf.set_font(family='Arial', style='B', size=8) # Row 5 pdf.cell(w=30, h=6, txt='Hypoapneas', align='L', border=1) pdf.set_font(family='Arial', style='', size=8) pdf.cell(w=15, h=6, txt='4.3', align='C', border=1) pdf.cell(w=15, h=6, txt='29', align='C', border=1) pdf.cell(w=15, h=6, txt='21.7', align='C', border=1) pdf.cell(w=15, h=6, txt='127', align='C', border=1) pdf.cell(w=14, h=6, txt='1', align='C', border=1) pdf.cell(w=14, h=6, txt='3', align='C', border=1) pdf.cell(w=14, h=6, txt='2', align='C', border=1) pdf.cell(w=14, h=6, txt='23', align='C', border=1) pdf.cell(w=14, h=6, txt='0', align='C', border=1, ln=1) pdf.set_font(family='Arial', style='B', size=8) # Row 6 pdf.cell(w=30, h=6, txt='RERAs', align='L', border=1) pdf.set_font(family='Arial', style='', size=8) pdf.cell(w=15, h=6, txt='4.3', align='C', border=1) pdf.cell(w=15, h=6, txt='29', align='C', border=1) pdf.cell(w=15, h=6, txt='21.7', align='C', border=1) pdf.cell(w=15, h=6, txt='127', align='C', border=1) pdf.cell(w=14, h=6, txt='1', align='C', border=1) pdf.cell(w=14, h=6, txt='3', align='C', border=1) pdf.cell(w=14, h=6, txt='2', align='C', border=1) pdf.cell(w=14, h=6, txt='23', align='C', border=1) pdf.cell(w=14, h=6, txt='0', align='C', border=1, ln=1) pdf.set_font(family='Arial', style='B', size=8) # Row 7 pdf.cell(w=30, h=6, txt='Total', align='L', border=1) pdf.set_font(family='Arial', style='', size=8) pdf.cell(w=15, h=6, txt='4.3', align='C', border=1) pdf.cell(w=15, h=6, txt='29', align='C', border=1) pdf.cell(w=15, h=6, txt='21.7', align='C', border=1) pdf.cell(w=15, h=6, txt='127', align='C', border=1) pdf.cell(w=14, h=6, txt='1', align='C', border=1) pdf.cell(w=14, h=6, txt='3', align='C', border=1) pdf.cell(w=14, h=6, txt='2', align='C', border=1) pdf.cell(w=14, h=6, txt='23', align='C', border=1) pdf.cell(w=14, h=6, txt='0', align='C', border=1, ln=1) pdf.set_font(family='Arial', style='B', size=8) # Row 8 pdf.cell(w=90, h=6, txt='Time in Position', align='L', border=1) pdf.set_font(family='Arial', style='', size=8) pdf.cell(w=14, h=6, txt='1', align='C', border=1) pdf.cell(w=14, h=6, txt='3', align='C', border=1) pdf.cell(w=14, h=6, txt='2', align='C', border=1) pdf.cell(w=14, h=6, txt='23', align='C', border=1) pdf.cell(w=14, h=6, txt='0', align='C', border=1, ln=1) pdf.set_font(family='Arial', style='B', size=8) # Row 9 pdf.cell(w=90, h=6, txt='Position', align='L', border=1) pdf.cell(w=14, h=6, txt='1', align='C', border=1) pdf.cell(w=14, h=6, txt='3', align='C', border=1) pdf.cell(w=14, h=6, txt='2', align='C', border=1) pdf.cell(w=14, h=6, txt='23', align='C', border=1) pdf.cell(w=14, h=6, txt='0', align='C', border=1, ln=1) # Output pdf.output('sibel-report.pdf', 'F')
def image_adder(no_of_pages = 0, page_dimension = (0,0), big_frame_dimension = (0, 0), frame_dimension = (0,0), padding_btw_frames = (1,1), image_resize = (0,0), circle_required = False, repetition = 1): dimensions_page = (px_to_pt_converter(page_dimension[0]), px_to_pt_converter(page_dimension[1])) if image_resize[0] == 0 or image_resize[1] == 0: image_resize = frame_dimension # Creating a directory where all the images will be saved directory = BASE_DIR + "/uploader/qrcodes/" try: mkdir(directory) except FileExistsError: print("Directory already exists! Need to delete it.") rmtree(directory) mkdir(directory) except OSError: print("Error creating a directory with name \'qrcodes\'") raise OSError else: print("Successfully created a directory with name \'qrcodes\'") try: # Extract zip files to a folder extractZip(directory) except FileNotFoundError: print("Error occurred not able to find the directory!") raise FileNotFoundError except RuntimeError: print("Runtime error while processing zipfiles!") raise RuntimeError try: # Directory of the images are required. images = resize_images_replicate_and_fetch(directory, image_resize, repetition) except IOError: print("Either file doesn't exist or image cannot be opened and identified!") rmtree(directory) raise IOError # print(images) TOTAL_IMAGES = len(images) index_images = 0 # Incrementing this value for the filename. suffix_filename = 1 while index_images < TOTAL_IMAGES: # Initialize pdf variable. pdf = FPDF('P', 'pt', dimensions_page) # Add a page to the pdf pdf.add_page() # print(pdf.get_x(), pdf.get_y()) pdf.set_font('Arial', 'B', 10) # Big frame dimensions_bigframe = (px_to_pt_converter(page_dimension[0]-50), px_to_pt_converter(page_dimension[1]-50)) default_current_pos_x = pdf.get_x() default_current_pos_y = pdf.get_y() pdf.rect(pdf.get_x(), pdf.get_y(), dimensions_bigframe[0], dimensions_bigframe[1], style = 'D') # Frame pdf.set_x(default_current_pos_x) pdf.set_y(default_current_pos_y) dimensions_frame = (int(px_to_pt_converter(frame_dimension[0])),int(px_to_pt_converter(frame_dimension[1]))) current_pos_x = default_current_pos_x current_pos_y = default_current_pos_y for row in nm.arange(current_pos_y, dimensions_bigframe[1], dimensions_frame[1]+padding_btw_frames[1]): for col in nm.arange(current_pos_x, dimensions_bigframe[0], dimensions_frame[0]+padding_btw_frames[0]): if ((col + dimensions_frame[0]) > dimensions_bigframe[0]) or ((row + dimensions_frame[1]) > dimensions_bigframe[1]): break position_in_x_direction = col+px_to_pt_converter(padding_btw_frames[0]) position_in_y_direction = row+px_to_pt_converter(padding_btw_frames[1]) pdf.rect(position_in_x_direction, position_in_y_direction, dimensions_frame[0], dimensions_frame[1], style = 'D') if index_images < TOTAL_IMAGES: try: load_image_to_pdf(pdf, directory + images[index_images], position_in_x_direction, position_in_y_direction, dimensions_frame[0], dimensions_frame[1], circle_required) except FileNotFoundError: rmtree(directory) raise FileNotFoundError # processed images are removed remove(directory + images[index_images]) pdf.set_x(col+dimensions_frame[0]) pdf.set_y(row) index_images += 1 pdf.set_y(row) pdf.set_x(current_pos_x) # output the pdf to a file. FILENAME = qrcodes(1...n).pdf FILE_NAME = BASE_DIR + "/uploader/" + FILE_NAME_PREFIX + str(suffix_filename) + ".pdf" pdf.output(FILE_NAME, 'F') suffix_filename = suffix_filename + 1 pdf.close() # Removing the directory after processing print("Removing the images directory after processing") rmtree(directory) print("Removing the zip files after processing") rmtree(BASE_DIR + "/uploader/zipfiles")
def create_invoice(o_id,file_no): cur.execute('SELECT * FROM `user orders` WHERE `order id` = %s',(o_id,)) for k in cur: order_id = 'Order id - ' + str(k[0]) name = 'Customer Name - ' + k[2] number = 'Customer Number - ' + k[3] address = 'Customer Address - ' + k[4] rest = 'Restaurant Name - ' + k[5] rest_address = 'Restaurant Address - ' + k[-3] rest_number = 'Restaurant Number - ' + k[-2] ord_time = 'Order Time - ' + str(k[-1]) item = k[6].split(',') item.pop() quantity = k[7].split(',') quantity.pop() price = k[8].split(',') price.pop() date = 'Order Date - ' + str(k[9]) total_quantity = 0 total_price = 0 for i in range(len(item)): total_quantity += int(quantity[i]) total_price += int(price[i]) * int(quantity[i]) pdf = FPDF() pdf.add_page() pdf.set_font('Arial', size = 14) pdf.cell(200,10, txt = 'Python Project', ln = 1, align = 'C') pdf.cell(200,5, txt = 'Food Ordering Program', ln = 1, align = 'C') pdf.dashed_line(34, 27, 185, 27, dash_length = 1) pdf.cell(200,12, txt = 'Invoice', ln = 1, align = 'C') pdf.dashed_line(34, 35, 185, 35, dash_length = 1) pdf.set_left_margin(33) pdf.cell(200,8, txt = order_id, ln = 1, align = 'L') pdf.cell(200,7, txt = date, ln = 1, align = 'L') pdf.cell(200,7, txt = ord_time, ln = 1, align = 'L') pdf.cell(200,7, txt = rest, ln = 1, align = 'L') pdf.cell(200,7, txt = rest_number, ln = 1, align = 'L') pdf.cell(200,7, txt = rest_address, ln = 1, align = 'L') pdf.cell(200,7, txt = name, ln = 1, align = 'L') pdf.cell(200,7, txt = number, ln = 1, align = 'L') pdf.cell(200,7, txt = address, ln = 1, align = 'L') pdf.dashed_line(34, 110, 185, 110, dash_length = 1) pdf.set_y(104) pdf.set_x(38) pdf.cell(200, 22, txt = 'Item', ln = 1) pdf.set_y(104) pdf.set_x(120) pdf.cell(200, 22, txt = 'Quantity', ln = 1) pdf.set_y(104) pdf.set_x(160) pdf.cell(200, 22, txt = 'Price', ln = 1) pdf.dashed_line(34, 120, 185, 120, dash_length = 1) for i in range(len(item)): pdf.set_x(38) y = pdf.get_y() pdf.cell(200, 10, txt = str(item[i]), ln = 1) pdf.set_y(y) pdf.set_x(125) pdf.cell(200, 10, txt = quantity[i], ln = 1) pdf.set_y(y) pdf.set_x(162) pdf.cell(200, 10, txt = price[i] + '.00', ln = 1) pdf.dashed_line(34, pdf.get_y() + 1.5, 185, pdf.get_y() + 1.5, dash_length = 1) pdf.set_x(38) y = pdf.get_y() pdf.cell(200, 17, txt = 'Total', ln = 1) pdf.set_y(y) pdf.set_x(125) pdf.cell(200, 17, txt = str(total_quantity), ln = 1) pdf.set_y(y) pdf.set_x(162) pdf.cell(200,17, txt = str(total_price) + '.00', ln = 1) y = pdf.get_y() - 10 pdf.set_y(y) pdf.set_x(38) pdf.cell(200, 17, txt = 'GST(18%)', ln = 1) pdf.set_y(y) pdf.set_x(125) pdf.cell(200, 17, txt = str(total_quantity), ln = 1) pdf.set_y(y) pdf.set_x(162) tax = str(total_price * (18/100)) fin_tax = '' cnt = 0 for i in tax: if i == '.': fin_tax = fin_tax + tax[cnt:cnt + 3] break else: fin_tax = fin_tax + i cnt += 1 pdf.cell(200, 17, txt = fin_tax, ln = 1) pdf.dashed_line(34, pdf.get_y() - 3, 185, pdf.get_y() - 3, dash_length = 1) y = pdf.get_y() - 5 pdf.set_y(y) pdf.set_x(38) pdf.cell(200, 17, txt = 'Grand Total', ln = 1) pdf.set_y(y) pdf.set_x(125) pdf.cell(200, 17, txt = str(total_quantity), ln = 1) pdf.set_y(y) pdf.set_x(162) fin_tot_0 = str(total_price + float(fin_tax)) fin_tot = '' cnt = 0 for i in fin_tot_0: if i == '.': fin_tot = fin_tot + fin_tot_0[cnt:cnt + 3] break else: fin_tot = fin_tot + i cnt += 1 pdf.cell(200,17, txt = fin_tot, ln = 1) pdf.dashed_line(34, pdf.get_y() - 3, 185, pdf.get_y() - 3, dash_length = 1) pdf.set_x(pdf.get_x() - 20) pdf.cell(200,17, txt = 'Thank you for ordering', ln = 1, align = 'C') pdf.set_y(pdf.get_y() - 8) pdf.set_x(pdf.get_x() - 20) pdf.cell(200,17, txt = 'We hope you have a great day!', ln = 1, align = 'C') file_name = os.getcwd() + '/Invoice/Invoice_' + str(file_no) + '.pdf' pdf.output(name = file_name) return file_name
def make_bulletin(): global y_appr global p p = FPDF('L', 'cm', 'A4') p.set_margins( marge, marge, marge) # marges (pas de marge_bottom, mais ligne suivante aide) p.set_auto_page_break( False ) # empêcher les page break automatiques (donc ~ pas de marge en bas) p.add_page() ################################# # Logo + coordonnées du lycée # ################################# # Logo p.image('logo_lycée.png', marge, marge, w=w_logo) # Adresse p.set_font('Arial', '', 7) p.set_xy(w_logo + marge, marge) adr_lycee = "Académie de Créteil\nLycée Polyvalent Louise Michel\n7 Rue Pierre Marie Derrien\n94500 Champigny-sur-Marne\nTél. : 01.48.82.07.35" p.multi_cell(w_adr_lycee, h_cell - 0.1, adr_lycee, aff_bord, 'C', False) ############################### # En-tête période + vie sco # ############################### # Titres en gras: bulletin de période, vie scolaire p.set_font('Arial', 'B', 9) p.cell(w_periode, h_cell, "Bulletin du " + periode.lower(), aff_bord, 0, 'C') p.cell(0, h_cell, "Vie scolaire", aff_bord, 0, 'C') # ligne horizontale x0 = marge + w_logo + w_adr_lycee x1 = width - marge y0 = marge + h_cell y1 = marge + h_cell p.line(x0, y0, x1, y1) # Infos de la classe p.set_font('Arial', '', 9) p.set_xy(x0, y0) # on commence au début de la ligne p.cell(w_infos_classe, h_cell, 'Année scolaire: %s' % annee_sco, aff_bord, 2, 'L') p.cell(w_infos_classe, h_cell, 'Classe: %s' % classe, aff_bord, 2, 'L') # PP: on peut en avoir plusieurs. Tri des noms et affichage correct. if len(prof_principal) == 1: PP = prof_principal[0] else: prof_principal.sort(key=lambda x: x.split(" ")[-1] ) # on trie par nom sans considérer M/Mme PP = '' for i in range(len(prof_principal)): PP += prof_principal[i] PP += '\n ' p.multi_cell(w_infos_classe, h_cell, 'PP: %s' % PP, aff_bord, 'L') p.set_xy(x0 + w_infos_classe, y0) # prénom élève p.set_font('Arial', 'B', 9) p.cell(w_periode - w_infos_classe, h_cell, nom, aff_bord, 2, 'L') # Infos persos élève (TODO) p.set_font('Arial', '', 9) if genre == 'M' or genre == 'I': infos_perso = "Né le %s\nINE : %s" % (date_naissance, INE) if genre == 'F': infos_perso = "Née le %s\nINE : %s" % (date_naissance, INE) p.multi_cell(w_periode - w_infos_classe, h_cell, infos_perso, aff_bord, 'L') # Absences + appréciation vie sco # TODO: Appréciation vie scolaire p.set_xy(p.get_x(), p.get_y() - h_cell) texte_viesco = "Absences : %s demi-journée" % abs if int(abs) > 1: texte_viesco += "s" texte_viesco += " dont %s non-réglée" % abs_non_reglees if int(abs_non_reglees) > 1: texte_viesco += "s" texte_viesco += ".\nAppréciation : %s" % appr_vie_sco p.multi_cell(0, h_cell, texte_viesco, aff_bord, 'L') ######################## # Bloc appréciations # ######################## # NOTE: On veut faire apparaître les appréciations dans un ordre précis # hardcodé dans ordre_matieres # Matières du tronc commun i = 0 for matiere in ordre_matieres: infos_appr = (matiere, moyennes[matiere].get('prof', ''), moyennes[matiere].get('appreciation', '')) ligne_appreciation(x_appr, y_appr + i * height_appr, infos_appr) i += 1 # On vérifie s'il n'y a pas d'option à ajouter for m in moyennes: if m == "Vie scolaire": continue # L'appréciation vie sco n'apparaît pas ici if m not in ordre_matieres: infos_appr = (m, moyennes[m].get('prof', ''), moyennes[m].get('appreciation', '')) ligne_appreciation(x_appr, y_appr + i * height_appr, infos_appr) i += 1 ################### # Bloc moyennes # ################### # Vu qu'on a un template fixe, on va se contenter d'appeler des fonctions bien définies # On construit des lignes de 3 blocs, dans l'ordre souhaité des matières. # Ligne FR/EN/ES temp_dict = { ordre_matieres[i]: moyennes[ordre_matieres[i]]['moyennes'] for i in range(0, 3) } ligne_eval(x_bloc, y_bloc, temp_dict) # Ligne HG/EMC/SES temp_dict = { ordre_matieres[i]: moyennes[ordre_matieres[i]]['moyennes'] for i in range(3, 6) } ligne_eval(x_bloc, y_bloc + 7 * h_cell + h_offset_blocs, temp_dict) # Ligne Maths/PC/SVT temp_dict = { ordre_matieres[i]: moyennes[ordre_matieres[i]]['moyennes'] for i in range(6, 9) } ligne_eval(x_bloc, y_bloc + 2 * (7 * h_cell + h_offset_blocs), temp_dict) # Selon la maquette, 2 situations: # - Soit on a deux blocs sur la dernière ligne (EPS et SNT) # - Soit on a trois blocs sur la dernière ligne (EPS, SNT, option) temp_dict = { ordre_matieres[i]: moyennes[ordre_matieres[i]]['moyennes'] for i in range(9, 11) } # On cherche l'option skip = 1 # Par défaut, pas d'option donc 1 bloc masqué for m in moyennes: if m == 'Vie scolaire': # on ignore la moyenne de vie sco (mais elle existe pour pouvoir mettre une appr à l'élève) continue if m not in ordre_matieres: # Si on trouve une option (qui n'est pas dans l'ordre de base) # On l'ajoute à temp_dict pour que les moyennes sortent temp_dict[m] = moyennes[m]['moyennes'] skip = 0 # ... et on ne saute pas le dernier bloc ligne_eval(x_bloc, y_bloc + 3 * (7 * h_cell + h_offset_blocs), temp_dict, skip=skip) # Légende des couleurs sous les blocs legende(x_bloc, y_bloc + 4 * (7 * h_cell + h_offset_blocs)) ############################# # Appr. générale/mentions # ############################# # Appréciation de la direction/PP p.set_font('Arial', 'B', 8) p.set_xy(x_appr_dir, y_appr_dir) p.cell(w_prof, h_cell, 'Appréciation globale :', aff_bord, 0) p.set_font('Arial', '', 8) p.multi_cell(0, h_cell, appr_dir, aff_bord, 'L') # Mention # TODO: Question à poser: "mention:" apparaît toujours même si pas de mention ? p.set_font('Arial', 'B', 8) p.set_xy(x_appr_dir, y_appr_dir + 5 * h_cell) p.cell(w_prof / 2, h_cell, 'Mention :', aff_bord, 0) p.set_font('Arial', '', 8) p.cell(0, h_cell, mention, aff_bord, 0) #################### # Signature chef # #################### # Mention "le chef d'établissement" + signature p.set_xy(x_chef, y_chef) p.cell(w_prof, h_cell, "Le chef d'établissement", aff_bord, 0) #p.image(signature,p.get_x(),p.get_y()-0.5*h_cell, h=h_signature) ##################### # Adresse du parent # ##################### p.add_page(orientation='P', format="A4") p.set_xy(x_parent, y_parent) p.set_font('Arial', 'B', 12) p.multi_cell(0, h_cell * 1.25, parent_nom, aff_bord, 'L') # Le pointeur a besoin de sauter 1 ou 2 lignes # selon le nombre de noms affichés (présence de \n si 2 noms) if '\n' in parent_nom: p.set_xy(x_parent, y_parent + 2.5 * h_cell) else: p.set_xy(x_parent, y_parent + 1.25 * h_cell) p.set_font('Arial', '', 12) p.multi_cell(0, h_cell * 1.25, parent_adresse, aff_bord, 'L') ### Création du fichier fname = nom + str(numero_bulletin) try: p.output('bulletin/%s.pdf' % fname, 'F') except FileNotFoundError as e: os.mkdir("bulletin") p.output('bulletin/%s.pdf' % fname, 'F')
def makePDF(printed_values, pdf_save_path): report_no = printed_values[0] # printing parameters # enable generalization # currenty set to printing on A4 format (210x297 mm) W = 190 H = 278 f_size = 5 # font size c_height = 0.02 * H # cell height rep = FPDF() rep.add_page() if find_font_file('segoeui.ttf') != []: rep.add_font('Segoe', '', find_font_file('segoeui.ttf')[0], uni=True) rep.add_font('Segoe', 'B', find_font_file('segoeuib.ttf')[0], uni=True) f_type = "Segoe" # font type if find_font_file('arial.ttf') != []: rep.add_font('Arial', '', find_font_file('arial.ttf')[0], uni=True) rep.add_font('Arial', 'B', find_font_file('arialbd.ttf')[0], uni=True) f_type = "Arial" # font type if find_font_file('DejaVuSans.ttf') != []: rep.add_font('DejaVu', '', find_font_file('DejaVuSans.ttf')[0], uni=True) rep.add_font('DejaVu', 'B', find_font_file('DejaVuSans-Bold.ttf')[0], uni=True) f_type = "DejaVu" # font type rep.set_font(f_type, 'B', size=5 * f_size) rep.cell(0.8 * W, 2.5 * c_height, txt="OPIS ZDARZENIA", align="C", border=1, ln=0) rep.set_font(f_type, 'B', size=3 * f_size) rep.cell(0.2 * W, 2.5 * c_height, txt=" LP. " + str(report_no), align="L", border=1, ln=1) rep.ln(c_height) rep.set_font(f_type, 'B', size=2 * f_size) left_margin = rep.get_x() ybefore = rep.get_y() rep.multi_cell(0.33 * W, 1.2 * c_height, txt=" DATA WYJAZDU:\n " + printed_values[1], align="L", border=1) rep.set_xy(W * 0.33 + left_margin, ybefore) rep.multi_cell(0.33 * W, 1.2 * c_height, txt=" GODZINA WYJAZDU:\n " + printed_values[2], align="L", border=1) rep.set_xy(W * 0.66 + left_margin, ybefore) rep.multi_cell(0.34 * W, 1.2 * c_height, txt=" NA MIEJSCU: \n " + printed_values[3], align="L", border=1) ybefore = rep.get_y() left_margin = rep.get_x() rep.multi_cell(0.33 * W, 2 * c_height, txt=" MIEJSCE ZDARZENIA:\n " + printed_values[4], align="L", border=1) rep.set_xy(W * 0.33 + left_margin, ybefore) rep.multi_cell(0.67 * W, 2 * c_height, txt=" RODZAJ ZDARZENIA:\n " + printed_values[5], align="L", border=1) rep.ln(c_height) ybefore = rep.get_y() rep.multi_cell(0.33 * W, 1.2 * c_height, txt=" DOWODCA SEKCJI:\n " + printed_values[6], align="L", border=1) rep.set_xy(W * 0.33 + left_margin, ybefore) rep.multi_cell(0.33 * W, 1.2 * c_height, txt=" DOWODCA AKCJI:\n " + printed_values[7], align="L", border=1) rep.set_xy(W * 0.66 + left_margin, ybefore) rep.multi_cell(0.34 * W, 1.2 * c_height, txt=" KIEROWCA: \n " + printed_values[8], align="L", border=1) ybefore = rep.get_y() rep.multi_cell(0.33 * W, 2 * c_height, txt=" SPRAWCA:\n " + printed_values[9], align="L", border=1) rep.set_xy(left_margin, ybefore + 4 * c_height) rep.multi_cell(0.33 * W, 2 * c_height, txt=" POSZKODOWANY:\n " + printed_values[10], align="L", border=1) rep.set_xy(W * 0.33 + left_margin, ybefore) rep.multi_cell(0.67 * W, 4 * c_height, txt=" SEKCJA:\n " + printed_values[11], align="L", border=1) rep.ln(c_height) rep.multi_cell(1 * W, 5 * c_height, txt=" SZCZEGOLY ZDARZENIA:\n " + printed_values[12], align="L", border=1) rep.ln(c_height) ybefore = rep.get_y() rep.multi_cell(0.2 * W, 2 * c_height, txt=" DATA POWROTU:\n " + printed_values[13], align="L", border=1) rep.set_xy(W * 0.2 + left_margin, ybefore) rep.multi_cell(0.35 * W, 2 * c_height, txt=" GODZ. ZAKONCZ.: " + printed_values[14], align="L", border=1) rep.set_xy(W * 0.2 + left_margin, ybefore + 2 * c_height) rep.multi_cell(0.35 * W, 2 * c_height, txt=" GODZ. W REMIZIE.: " + printed_values[15], align="L", border=1) rep.set_xy(W * 0.55 + left_margin, ybefore) rep.multi_cell(0.2 * W, 2 * c_height, txt=" STAN LICZNIKA: \n " + printed_values[16], align="C", border=1) rep.set_xy(W * 0.75 + left_margin, ybefore) rep.multi_cell(0.25 * W, 2 * c_height, txt=" KM. DO MIEJSCA ZD: \n " + printed_values[17], align="C", border=1) modDate = str(printed_values[18])[11:].replace(":", "") path = pdf_save_path + "/" + str(report_no) + "_" + str( printed_values[4]) + "_" + str( printed_values[1]) + "_" + modDate + ".pdf" rep.output(path)
pdf.cell(table_width, table_height, 'Score 0~4:', 1, 1) for row in Table_Data_0_4: for item in row: split_item = item.split() divide = math.ceil(len(split_item) / char_per_line) mod = len(split_item) % char_per_line for i in range(divide): split_portion = split_item[i * char_per_line:(i + 1) * char_per_line:] each_portion = ' '.join(split_portion) pdf.cell(table_width, table_height, each_portion, 1, 1) # if i == (divide - 1): # split_portion = split_item[i*char_per_line:i*char_per_line+mod:] # each_portion = ' '.join(split_portion) # pdf.cell(table_width, table_height, each_portion, 1, 1) pdf.set_xy(int(pdf.get_x()), int(pdf.get_y()) + 20) pdf.cell(table_width, table_height, 'Score 5~7:', 1, 1) for row in Table_Data_5_7: for item in row: split_item = item.split() divide = math.ceil(len(split_item) / char_per_line) mod = len(split_item) % char_per_line for i in range(divide): split_portion = split_item[i * char_per_line:(i + 1) * char_per_line:] each_portion = ' '.join(split_portion) pdf.cell(table_width, table_height, each_portion, 1, 1) pdf.output("App_Satisfication.pdf")
pdf.dashed_line(page_size['left'] + 1, header_y, page_size['end_x'] + 1, header_y, 1, 1) pdf.ln(2) # about section pdf.set_font(title_font, '', font_size['section_title']) pdf.cell(1, line_height['section'] - 1, data['sections']['about'], ln=2) pdf.set_font(text_font, '', font_size['text']) col_1_count = len(data['about']['introduction']) / 2 desc_y = pdf.get_y() for idx, desc in enumerate(data['about']['introduction']): if idx == col_1_count: pdf.set_y(desc_y) if idx < col_1_count: pdf.set_x(page_size['left'] + page_size['section_indent']) else: pdf.set_x(page_size['middle_x']) pdf.ellipse(pdf.get_x(), pdf.get_y() + 1.1, ellipse['size'], ellipse['size'], 'F') pdf.cell(ellipse['margin']) pdf.cell(1, line_height['text'] - 1, desc, ln=2) pdf.ln(page_size['section_margin']) # education section pdf.set_x(page_size['left']) pdf.set_font(title_font, '', font_size['section_title']) pdf.cell(1, line_height['section'] - 1, data['sections']['education'], ln=2) pdf.set_font(text_font, '', font_size['text']) for univ in data['education']['universities']: pdf.set_x(page_size['left'] + page_size['section_indent']) univ_y = pdf.get_y() pdf.set_font_size(font_size['text'] + 1) pdf.set_text_color(*brown) pdf.cell(1, line_height['text'], univ['name'], ln=2) pdf.set_font_size(font_size['text'])
def formatPdf(data): pdf = FPDF() pdf.add_page() pdf.set_font('Arial', 'B', 16) # title of the label pdf.cell(w = 0,h = 15, txt='Rivia.Ai', border=0, ln=1, align = 'C') # adding seller pdf.set_font('Arial', 'B', 12) pdf.cell(w = 95, h = 15, txt = "Sold By", border=0, ln = 0, align = 'L') pdf.set_font('Arial', '', 12) sellerName = "" if 'sold_by' in data.keys(): sellerName = str(data['sold_by']) pdf.cell(w = 95, h = 15, txt = sellerName, border=0, ln = 1, align = 'R') pdf.set_font('Arial', 'B', 12) pdf.cell(w = 95, h = 15, txt = "Delivered By", border=0, ln = 0, align = 'L') pdf.set_font('Arial', '', 12) deliveryAgent = "" if 'delivered_by' in data.keys(): deliveryAgent = str(data['delivered_by']) pdf.cell(w = 95, h = 15, txt = deliveryAgent, border=0, ln = 1, align = 'R') if 'shipping_address' in data.keys(): pdf.set_font('Arial', 'B', 12) address = "Shipping Address:\n" for part in data['shipping_address'].values(): address += part address += '\n' x = pdf.get_x() y = pdf.get_y() pdf.multi_cell(w = 95, h = 5, txt = address, border=0, align = 'L') p = pdf.get_x() q = pdf.get_y() x += 95 pdf.set_xy(x, y) pdf.set_font('Arial', 'B', 30) if 'payment' in data.keys(): if 'mode' in data['payment'].keys(): pdf.cell(w = 95, h = q-y, txt = str(data['payment']['mode']), border=0, ln = 1, align = 'C') pdf.set_xy(p, q) pdf.cell(w = 95, h = 10, txt = "", border=0, ln = 0, align = 'L') pdf.cell(w = 95, h = 10, txt = "", border=0, ln = 1, align = 'R') pdf.set_font('Arial', 'B', 12) pdf.cell(w = 95, h = 5, txt = "Order Date:", border=0, ln = 0, align = 'L') pdf.cell(w = 95, h = 5, txt = "Tracking ID:", border=0, ln = 1, align = 'R') pdf.set_font('Arial', '', 12) order_date = "" tracking_id = "" if 'order_date' in data.keys(): order_date = data['order_date'] if 'tracking_id' in data.keys(): tracking_id = data['tracking_id'] pdf.cell(w = 95, h = 5, txt = order_date, border=0, ln = 0, align = 'L') pdf.cell(w = 95, h = 5, txt = tracking_id, border=0, ln = 1, align = 'R') pdf.cell(w = 95, h = 10, txt = "", border=0, ln = 0, align = 'L') pdf.cell(w = 95, h = 10, txt = "", border=0, ln = 1, align = 'R') if 'line_items' in data.keys(): itemsToBeDilivered = [["PRODUCT", "DETAILS(opt)", "QTY"]] for item in data['line_items']: product = [] for productDetails in item.values(): product.append(str(productDetails)) itemsToBeDilivered.append(product) for r in itemsToBeDilivered: for c in range(3): if c != 2: pdf.cell(w = (190.00 / 3), h = 10, txt = str(r[c]), border=1, ln = 0, align = 'L') else: pdf.cell(w = (190.00 / 3), h = 10, txt = str(r[c]), border=1, ln = 1, align = 'L') pdf.set_font('Arial', 'B', 16) pdf.cell(w = 95, h = 20, txt = "Invoice Value ", border=0, ln = 0, align = 'C') cost = 0 if 'payment' in data.keys(): if 'amount' in data['payment'].keys(): cost = float(str(data['payment']['amount'])) pdf.cell(w = 95, h = 20, txt = "INR " + str(cost), border=0, ln = 1, align = 'C') returnAddress = "" if 'return_address' in data.keys(): for addr in data['return_address'].values(): returnAddress += str(addr) returnAddress += " " pdf.set_font('Arial', 'B', 14) pdf.cell(w = 0,h = 15, txt="Return Address:", border=0, ln=1, align = 'C') pdf.set_font('Arial', '', 14) pdf.cell(w = 0,h = 15, txt=returnAddress, border=0, ln=1, align = 'C') return pdf
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())
for page in range(pages): pdf.add_page() pdf.set_y(margin_top) for row in range(rows): pdf.set_x(margin_left) for column in range(columns): cell_id = start_id + (column + row * columns) qr_filename = image_folder + str(cell_id) + ".png" url = base_url + str(cell_id) # Generate QR CODE img = qrcode.make(url, border=0) img.save(qr_filename, "PNG") # Write in our QR code pdf.image( x=pdf.get_x() + image_border, y=pdf.get_y() + image_border, w=max_dimension - image_border * 2, h=max_dimension - image_border * 2, name=qr_filename, link=url, ) # Add the logo pdf.image( x=pdf.get_x() + max_dimension, y=pdf.get_y() + image_border, w=logo_width, h=logo_height, name=logo_filename, ) # Print the id
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()
class MathWorksheetGenerator: """class for generating math worksheet of specified size and main_type""" def __init__(self, type_: str, max_number: int, question_count: int): self.main_type = type_ self.max_number = max_number self.question_count = question_count self.pdf = FPDF() self.small_font_size = 10 self.middle_font_size = 15 self.large_font_size = 30 self.size = 21 self.tiny_pad_size = 2 self.pad_size = 10 self.large_pad_size = 30 self.num_x_cell = 4 self.num_y_cell = 2 self.font_1 = 'Times' self.font_2 = 'Arial' # From https://stackoverflow.com/questions/6800193/what-is-the-most-efficient-way-of-finding-all-the-factors-of-a # -number-in-python def factors(self, n: int): return set( reduce(list.__add__, ([i, n // i] for i in range(1, int(n**0.5) + 1) if n % i == 0))) def division_helper(self, num) -> [int, int, int]: # prevent num = 0 or divisor = 1 or divisor = dividend factor = 1 while not num or factor == 1 or factor == num: num = random.randint(0, self.max_number) # pick a factor of num; answer will always be an integer if num: factor = random.sample(self.factors(num), 1)[0] answer = int(num / factor) return [num, factor, answer] def generate_question(self) -> QuestionInfo: """Generates each question and calculate the answer depending on the type_ in a list To keep it simple, number is generated randomly within the range of 0 to 100 :return: list of value1, main_type, value2, and answer for the generated question """ num_1 = random.randint(0, self.max_number) num_2 = random.randint(0, self.max_number) if self.main_type == 'mix': current_type = random.choice(['+', '-', 'x', '/']) else: current_type = self.main_type if current_type == '+': answer = num_1 + num_2 elif current_type == '-': # avoid having a negative answer which is an advanced concept num_1, num_2 = sorted((num_1, num_2), reverse=True) answer = num_1 - num_2 elif current_type == 'x': answer = num_1 * num_2 elif current_type == '/': num_1, num_2, answer = self.division_helper(num_1) else: raise RuntimeError( f'Question main_type {current_type} not supported') return num_1, current_type, num_2, answer def get_list_of_questions(self, question_count: int) -> List[QuestionInfo]: """Generate all the questions for the worksheet in a list. Initially trying for unique questions, but allowing duplicates if needed (e.g. asking for 80 addition problems with max size 3 requires duplication) :return: list of questions """ questions = [] duplicates = 0 while len(questions) < question_count: new_question = self.generate_question() if new_question not in questions or duplicates >= 10: questions.append(new_question) else: duplicates += 1 return questions def make_question_page(self, data: List[QuestionInfo]): """Prepare a single page of questions""" page_area = self.num_x_cell * self.num_y_cell problems_per_page = self.split_arr(self.question_count, page_area) total_pages = len(problems_per_page) for page in range(total_pages): self.pdf.add_page(orientation='L') if problems_per_page[page] < self.num_x_cell: self.print_question_row(data, page * page_area, problems_per_page[page]) else: problems_per_row = self.split_arr(problems_per_page[page], self.num_x_cell) total_rows = len(problems_per_row) self.print_question_row(data, page * page_area, problems_per_row[0]) for row in range(1, total_rows): page_row = row * self.num_x_cell self.print_horizontal_separator() self.print_question_row(data, page * page_area + page_row, problems_per_row[row]) def split_arr(self, x: int, y: int): """Split x into x = y + y + ... + (x % y)""" quotient, remainder = divmod(x, y) if remainder != 0: return [y] * quotient + [remainder] return [y] * quotient def print_top_row(self, question_num: str): """Helper function to print first character row of a question row""" self.pdf.set_font(self.font_1, size=self.middle_font_size) self.pdf.cell(self.pad_size, self.pad_size, txt=question_num, border='LT', align='C') self.pdf.cell(self.size, self.pad_size, border='T') self.pdf.cell(self.size, self.pad_size, border='T') self.pdf.cell(self.pad_size, self.pad_size, border='TR') def print_second_row(self, num: int): """Helper function to print second character row of a question row""" self.pdf.set_font(self.font_2, size=self.large_font_size) self.pdf.cell(self.pad_size, self.size, border='L') self.pdf.cell(self.size, self.size) self.pdf.cell(self.size, self.size, txt=str(num), align='R') self.pdf.cell(self.pad_size, self.size, border='R') def print_second_row_division(self, num_1: int, num_2: int): """Helper function to print second character row of a question row for division""" self.pdf.set_font(self.font_2, size=self.large_font_size) self.pdf.cell(self.pad_size, self.size, border='L') self.pdf.cell(self.size, self.size, txt=str(num_2), align='R') x_cor = self.pdf.get_x() - 3 y_cor = self.pdf.get_y() self.pdf.image(name='division.png', x=x_cor, y=y_cor) self.pdf.cell(self.size, self.size, txt=str(num_1), align='R') self.pdf.cell(self.pad_size, self.size, border='R') def print_third_row(self, num: int, current_type: str): """Helper function to print third character row of a question row""" self.pdf.cell(self.pad_size, self.size, border='L') self.pdf.cell(self.size, self.size, txt=current_type, align='L') self.pdf.cell(self.size, self.size, txt=str(num), align='R') self.pdf.cell(self.pad_size, self.size, border='R') def print_third_row_division(self): """Helper function to print third character row of a question row for division""" self.pdf.cell(self.pad_size, self.size, border='L') self.pdf.cell(self.size, self.size, align='L') self.pdf.cell(self.size, self.size, align='R') self.pdf.cell(self.pad_size, self.size, border='R') def print_bottom_row(self): """Helper function to print bottom row of question""" self.pdf.cell(self.pad_size, self.size, border='LB') self.pdf.cell(self.size, self.size, border='TB') self.pdf.cell(self.size, self.size, border='TB') self.pdf.cell(self.pad_size, self.size, border='BR') def print_bottom_row_division(self): """Helper function to print bottom row of question""" self.pdf.cell(self.pad_size, self.size, border='LB') self.pdf.cell(self.size, self.size, border='B') self.pdf.cell(self.size, self.size, border='B') self.pdf.cell(self.pad_size, self.size, border='BR') def print_edge_vertical_separator(self): """Print space between question for the top or bottom row""" self.pdf.cell(self.pad_size, self.pad_size) def print_middle_vertical_separator(self): """Print space between question for the second or third row""" self.pdf.cell(self.pad_size, self.size) def print_horizontal_separator(self): """Print line breaker between two rows of questions""" self.pdf.cell(self.size, self.size) self.pdf.ln() def print_question_row(self, data, offset, num_problems): """Print a single row of questions (total question in a row is set by num_x_cell)""" for x in range(0, num_problems): self.print_top_row(str(x + 1 + offset)) self.print_edge_vertical_separator() self.pdf.ln() for x in range(0, num_problems): if data[x + offset][1] == '/': self.print_second_row_division(data[x + offset][0], data[x + offset][2]) else: self.print_second_row(data[x + offset][0]) self.print_middle_vertical_separator() self.pdf.ln() for x in range(0, num_problems): if data[x + offset][1] == '/': self.print_third_row_division() else: self.print_third_row(data[x + offset][2], data[x + offset][1]) self.print_middle_vertical_separator() self.pdf.ln() for x in range(0, num_problems): if data[x + offset][1] == '/': self.print_bottom_row_division() else: self.print_bottom_row() self.print_edge_vertical_separator() self.pdf.ln() def make_answer_page(self, data): """Print answer sheet""" self.pdf.add_page(orientation='L') self.pdf.set_font(self.font_1, size=self.large_font_size) self.pdf.cell(self.large_pad_size, self.large_pad_size, txt='Answers', ln=1, align='C') for i in range(len(data)): self.pdf.set_font(self.font_1, size=self.small_font_size) self.pdf.cell(self.pad_size, self.pad_size, txt=f'{i + 1}:', border='TLB', align='R') self.pdf.set_font(self.font_2, size=self.small_font_size) self.pdf.cell(self.pad_size, self.pad_size, txt=str(data[i][3]), border='TB', align='R') self.pdf.cell(self.tiny_pad_size, self.pad_size, border='TRB', align='R') self.pdf.cell(self.tiny_pad_size, self.pad_size, align='C') if i >= 9 and (i + 1) % 10 == 0: self.pdf.ln()
now = datetime.datetime.now() # title is generated with today's date time picks_file = "reptilinks-picks-" + now.strftime("%Y-%m-%d %H%M%S") + ".pdf" title = "Orders: " + str(order_num_min) + " - " + str(order_num_max) # refer to https://pyfpdf.readthedocs.io/en/latest docs # for more information on how to use their libary to format a pdf pdf = FPDF(format="Letter") pdf.add_page() pdf.set_font('Times', '', 8) pdf.cell(70, 5, title, 0, 1) ############################################ # regular ############################################ x = pdf.get_x() y = pdf.get_y() # refer to layout.py file for PrintCells function def (xr, yr) = layout.PrintCells(pdf, "Regular", regular_products, x, y, y) ############################################ # Mini ############################################ (xm, ym) = layout.PrintCells(pdf, "Mini", mini_products, xr, yr, y) ############################################ # Non link ############################################ (xn, yn) = layout.PrintCells(pdf, "Non-link", non_sausage, xm, ym, y)
header_y, 1, 1) pdf.ln(2) # about section pdf.set_font(title_font, '', font_size['section_title']) pdf.cell(1, line_height['section'] - 1, data['sections']['about'], ln=2) pdf.set_font(text_font, '', font_size['text']) col_1_count = len(data['about']['introduction']) / 2 desc_y = pdf.get_y() for idx, desc in enumerate(data['about']['introduction']): if idx == col_1_count: pdf.set_y(desc_y) if idx < col_1_count: pdf.set_x(page_size['left'] + page_size['section_indent']) else: pdf.set_x(page_size['middle_x']) pdf.ellipse(pdf.get_x(), pdf.get_y() + 1.1, ellipse['size'], ellipse['size'], 'F') pdf.cell(ellipse['margin']) pdf.cell(1, line_height['text'] - 1, desc, ln=2) pdf.ln(page_size['section_margin']) # education section pdf.set_x(page_size['left']) pdf.set_font(title_font, '', font_size['section_title']) pdf.cell(1, line_height['section'] - 1, data['sections']['education'], ln=2) pdf.set_font(text_font, '', font_size['text']) for univ in data['education']['universities']: pdf.set_x(page_size['left'] + page_size['section_indent']) pdf.set_font_size(font_size['text'] + 1)
# pyFPDF # https://pyfpdf.readthedocs.io/en/latest/ from fpdf import FPDF # FPDF(orientation = 'P', unit = 'mm', format='A4') pdf = FPDF() pdf.add_page() pdf.set_font("Helvetica", "", 12) #pdf.text(5,10,"Hello, World!") #length = pdf.get_string_width("Hello, World! ") #pdf.text(5,15,"print(Hello, World!)") pdf.set_xy(20, 100) #fpdf.cell(w, h = 0, txt = '', border = 0, ln = 0, align = '', fill = False, link = '') pdf.cell(30, 5, "Hello, World!", border="LTBR", align="C") pdf.cell(0, 5, "Hola, Mundo!", border="LTBR", align="C", ln=2) pdf.cell(0, 5, "Olá, Mundo!", border="LTBR", align="C", ln=2) x, y = pdf.get_x(), pdf.get_y() print(x, y) pdf.set_text_color(47, 172, 155) pdf.text(x, y, "AAAAAAAAAAAA") pdf.output("output/myfirstpdf.pdf")
def createPDF(self, dict_person, stamp, date_doc): for faculty in dict_person: # формируем список с именами волонтеров sort_person_list = [i for i in dict_person[faculty]] # сортируем его sort_person_list.sort() # на основе отсортированного списка формируем новый словарь, с упорядоченным значением имен sort_dict = {} for name in sort_person_list: sort_dict[name] = dict_person[faculty][name] pdf = FPDF() pdf.add_page() pdf.add_font('DejaVu', '', 'DejaVuSansCondensed.ttf', uni=True) pdf.add_font('DejaVu', 'B', 'DejaVuSansCondensed-Bold.ttf', uni=True) pdf.set_font('DejaVu', 'B', 16) pdf.cell(0, 10, 'ОЦЕНОЧНАЯ ВЕДОМОСТЬ ПО ПРОЕКТУ', 0, 1, 'C') pdf.set_font('DejaVu', '', 12) pdf.cell(0, 10, 'Волонтеры: олимпиадный марафон(название проекта)', 0, 1, 'C') pdf.cell(0, 10, 'Сервисный проект (тип проекта)', 0, 1, 'C') pdf.cell(0, 10, 'Январь – май (срок выполнения проекта)', 0, 1, 'C') # Таблица 1 pdf.cell(30, 10, '', 0, 0, 'C') pdf.multi_cell(65, 7, 'Руководитель проекта:\nФИО \nДолжность\n\n', 1, 'L') pdf.set_y(pdf.get_y() - 28) pdf.set_x(pdf.get_x() + 65 + 30) pdf.multi_cell( 90, 7, 'Протасевич Тамара Анатольевна \nДиректор по профессиональной ориентации и работе с ' 'одаренными учащимися', 1, 'L') pdf.cell(30, 10, '', 0, 0, 'C') pdf.multi_cell(65, 7, 'Образовательная программа\n\n\n', 1, 'L') # устанавливаем позицию следующей мульти-ячейки pdf.set_xy(pdf.get_x() + 65 + 30, pdf.get_y() - 7 * 3) # расчет положения последней ячейки f = faculty + '\n\n' if 40 <= len( faculty) < 80 else faculty + '\n\n\n' if len( faculty) < 40 else faculty pdf.multi_cell(90, 7, f, 1, 'L') pdf.ln(20) # Таблица 2 заголовки w_cell1 = 90 w_cell2 = 40 w_cell3 = 30 w_cell4 = 30 h_cell = 5 * 3 pdf.set_font('DejaVu', 'B', 12) pdf.multi_cell(w_cell1, 5, '\nФИО\n\n', 1, 'C') pdf.set_xy(pdf.get_x() + w_cell1, pdf.get_y() - h_cell) pdf.multi_cell(w_cell2, 5, '\nКурс\n\n', 1, 'C') pdf.set_xy(pdf.get_x() + w_cell1 + w_cell2, pdf.get_y() - h_cell) pdf.multi_cell(w_cell3, 5, 'Оценка по 10-балльной шкале', 1, 'C') pdf.set_xy(pdf.get_x() + w_cell1 + w_cell2 + w_cell3, pdf.get_y() - h_cell) pdf.multi_cell(w_cell4, 5, 'Количество ЗЕ за проект', 1, 'C') # Таблица 2 тело pdf.set_font('DejaVu', '', 12) # добавляем строки таблице и заполняем содержимым переданного словарая с волонтерами for person in sort_dict: pdf.cell(90, 5, person, 1, 0, 'L') pdf.cell(40, 5, sort_dict[person][1], 1, 0, 'C') pdf.cell(30, 5, '10', 1, 0, 'C') grade = sort_dict[person][0] if grade < 3: value = '1' elif grade == 3: value = '2' else: value = '3' pdf.cell(30, 5, value, 1, 1, 'C') pdf.ln(5) # Вставляем дату pdf.cell(100, 5, f'Дата заполнения: {date_doc}', 0, 0, 'L') pdf.cell(90, 5, 'Протасевич Т.А.', 0, 1, 'R') if stamp: pdf.image('123.png', x=120, w=73, h=40.5) # путь сохранения файла path_save = faculty.replace('"', '').replace(':', '') a = f'{self._dirForSave}/{path_save}.pdf' # # сохраняем созданный документ pdf.output(a)