def generate(pdfname): datamanager = DataManager('127.0.0.1', 27017) pdf = FPDF() pdf.add_page() pdf.set_author('GRE Master') pdf.set_title('GRE Word') #pdf.set_font('Arial', 'B', 16) pdf.add_font('eunjin', '', 'Eunjin.ttf', uni=True) pdf.set_font('eunjin', '', 16) pdf.add_font('bangwool', '', 'Bangwool.ttf', uni=True) pdf.set_font('bangwool', '', 16) #pdf.add_font('DejaVu', '', 'DejaVuSansCondensed.ttf', uni=True) #pdf.set_font('DejaVu', '', 16) for row in datamanager.find(): text = row['text'] meanings = row['meaning'] synonyms = row['synonyms'] meaning = ','.join(meanings) synonym = u','.join(synonyms) line = '%s : %s \n synonyms : %s' % (text, meaning, synonym) #pdf.cell(20, 10, row['text'], 0, 0)# + ' ' + ','.join(row['meaning'])) pdf.multi_cell(0, 8, line, 1, 'J') pdf.output(pdfname, 'F')
def CreatePDF(copy_count): file_name = "question.txt" nameval_file = "NameVal.txt" header_data = ReadNameValFile(nameval_file) q_list = ReadQFile(file_name) for i in range(0, copy_count): pdf = FPDF() count = 1 pdf.add_page() pdf.set_title("Ranbir Roshan") #no effect pdf.set_subject("Ranbir Subject") #no effect pdf.set_author("Author Ranbir") pdf.set_auto_page_break('auto') pdf.set_creator("Ranbir Creator") PrintHeader(pdf, header_data) pdf.set_font("Arial", size=header_data.NormalLineFontSize) if (header_data.RandomQuestionOrder == "TRUE"): random.shuffle(q_list) if (header_data.PickQuestionCount < len(q_list) and header_data.PickQuestionCount > 0): list = random.sample(q_list, k=header_data.PickQuestionCount) else: list = q_list for question in q_list: #PrintQuestion(question, pdf, count, header_data) question.Print(pdf, header_data, "", count) count = count + 1 name = "sample_" + str(i) + ".pdf" pdf.output(name)
def imgs_to_pdf(): index = 0 pdf = FPDF() pdf.set_creator("刘小绪同学") pdf.set_author("刘小绪同学") pdf.add_page() for img in os.listdir(PATH): print(index) index += 1 pdf.image(PATH + img, w=190, h=280) pdf.output("articles.pdf")
def main(): """ Entry-point for the function. """ pdf = FPDF() pdf.set_display_mode('fullwidth') pdf.set_creator('Cavin Dsouza') pdf.set_author('bizarro') scrape(pdf) pdf.output("bizarro.pdf", "F") print("PDF created successfully.")
def plate(request): try: o = Order.objects.filter(session=request.shop_session, is_history=True).latest('id') config, create = ConfigModel.objects.get_or_create(id=1) domain = Site.objects.get_current().domain except: pass else: if config.organization and config.office1 and o.address and o.name: pdf = FPDF('P','mm','A4') pdf.set_author(domain) pdf.add_page() pdf.add_font('DejaVu', '', 'DejaVuSansCondensed.ttf', uni=True) pdf.add_font('DejaVuBold', '', 'DejaVuSansCondensed-Bold.ttf', uni=True) pdf.set_fill_color(229, 229, 229); pdf.set_font('DejaVu', '', 5); pdf.write(9, _(u"Created by %(date)s on %(domain)s. Order #%(id)d.") % {'date':datetime.datetime.now().strftime('%d.%m.%Y %H:%M'), 'domain':domain, 'id':o.id}) pdf.ln(9) pdf.set_font('DejaVuBold', '', 9); pdf.write(9, _(u"Recipient:")) pdf.ln(9) pdf.set_font('DejaVu', '', 8); if config.office1: pdf.write(5, _(u"Address: %s") % config.office1) pdf.ln(5) if config.organization: pdf.write(5, _(u"Name: %s") % config.organization) pdf.ln(5) pdf.set_font('DejaVuBold', '', 9); pdf.write(9, _(u"Sender:")) pdf.ln(9) pdf.set_font('DejaVu', '', 8); if o.address: pdf.write(5, _(u"Address: %s") % o.address) pdf.ln(5) if o.name: pdf.write(5, _(u"Name: %s") % o.name) pdf.ln(9) pdf.set_font('DejaVu', '', 5); pdf.write(5, _(u"Cut and paste on the packaging")) pdf.ln(5) s = pdf.output('Plate.pdf', 'S') response = HttpResponse(s, mimetype='application/pdf; charset=cp1251') response['Content-Disposition'] = 'attachment; filename=plate.pdf' return response return HttpResponse('')
def generate_book(self, now_, cameras_): page_width = 260 page_height = 200 text_large = 15 text_regular = 11 title = 'now' edition = '{} UTC'.format(now_) pdf = FPDF('P', 'mm', (page_width, page_height)) pdf.set_author('Birk Weiberg') pdf.set_title('{} = {}'.format(title, edition)) pdf.set_margins(0, 0, 0) pdf.add_page() pdf.set_font('Arial', 'B', text_large) pdf.cell(0, 0.5 * page_height, '', 0, 1, 'C') pdf.cell(0, 0, title, 0, 0, 'C') pdf.add_page() pdf.add_page() pdf.cell(0, 0.5 * page_height, '', 0, 1, 'C') pdf.cell(0, 0, edition, 0, 0, 'C') pdf.add_page() pdf.set_font('Arial', '', text_regular) pdf.cell(0, 0.8 * page_height, '', 0, 1, 'C') pdf.cell(0, 0.5 * text_regular, 'Birk Weiberg, 2016', 0, 1, 'C') pdf.cell(0, 0.5 * text_regular, 'https://github.com/birk/now-book', 0, 1, 'C') pdf.add_page() for c in cameras_: pdf.add_page() pdf.add_page() try: w, h = self.get_prop_size(c.file, 0.7 * page_width, 0.6 * page_height) except (OSError) as exc: print('Error loading image from {} - {}'.format( c.location, c.url)) return pdf.image(c.file, 0.5 * (page_width - w), 0.4 * (page_height - h), w, h) pdf.cell(0, 0.85 * page_height, '', 0, 1, 'C') pdf.cell(0, 0.5 * text_regular, c.location_str, 0, 1, 'C') pdf.link(0.4 * page_width, 0.84 * page_height, 0.2 * page_width, 0.04 * page_height, c.link) pdf.add_page() pdf.add_page() while pdf.page % 4 != 0: pdf.add_page() file_name = '{}-{}.pdf'.format( title, str(now_).replace(' ', '-').replace(':', '-')) pdf.output(file_name, 'F') print('now-book: {}'.format(file_name))
def generate_pdf(results, path): from fpdf import FPDF pdf = FPDF() pdf.add_page() pdf.set_font('Arial', 'B', 12) pdf.cell(40, 10, 'Hello World!') pdf.output('tuto1.pdf', 'F') pdf = PDF() pdf.set_title(title) pdf.set_author('Jules Verne') pdf.print_chapter(1, 'A RUNAWAY REEF', '20k_c1.txt') pdf.print_chapter(2, 'THE PROS AND CONS', '20k_c2.txt') pdf.output('tuto3.pdf', 'F')
def export_pdf(post_res): pdf = FPDF() pdf.add_page() pdf.set_font('Arial', 'B', size=16) pdf.cell( 200, 10, txt='Approval for using Infliximab in Ankylosing Spondylitis Patient', ln=1, align='C') pdf.set_font('Arial', size=12) pdf.cell(200, 10, txt='Weight: ' + post_res[0], ln=1, align='C') pdf.cell(200, 10, txt='Date of evaluation: ' + post_res[1], ln=1, align='C') pdf.cell(200, 10, txt='Initial BASDAI: ' + post_res[2], ln=1, align='C') pdf.cell(200, 10, txt='Current BASDAI: ' + post_res[3], ln=1, align='C') pdf.cell(200, 10, txt='Initial Physician Global Assessment: ' + post_res[4], ln=1, align='C') pdf.cell(200, 10, txt='Current Physician Global Assessment: ' + post_res[5], ln=1, align='C') pdf.cell(200, 10, txt='Additional Information from Doctor: ' + post_res[6], ln=1, align='C') pdf.set_author('Kasidech Chumkun') full_filename = os.path.join(app.config['UPLOAD_FOLDER'], 'result/sample_form.pdf') pdf.output(full_filename) return full_filename
def main(): #read all files from a given directory path = "./figures" imagelist = os.listdir(path) #print(imagelist) #Creating first pdf page image image1 = Image.open(path + '\\' + imagelist[0]) image2 = Image.open(path + '\\' + imagelist[1]) get_concat_v(image1, image2).save('./pdf/concat1.png') #Creating second pdf page image image3 = Image.open(path + '\\' + imagelist[2]) image4 = Image.open(path + '\\' + imagelist[3]) image6 = Image.open(path + '\\' + imagelist[5]) imageaux = get_concat_v(image3, image4) get_concat_v(imageaux, image6).save('./pdf/concat2.png') imagelist2 = [ 'concat1.png', 'concat2.png', './figures/z_network_graph.png' ] #Creating pdf pdf = FPDF() pdf.set_author('March') #First page pdf.add_page() pdf.set_font('Arial', 'B', 14) pdf.cell(90, 9, 'Cumulative Returns & Drawdowns', 1, 0, 'C') pdf.ln(10) pdf.image('pdf\\' + imagelist2[0], w=195, h=230) #Second page pdf.add_page() pdf.set_author('March') pdf.set_font('Arial', 'B', 12) pdf.cell(50, 8, 'Portfolio Analysis', 1, 0, 'C') pdf.ln(10) pdf.image('pdf\\' + imagelist2[1], w=195, h=250) #Third page pdf.add_page() pdf.set_author('March') pdf.set_font('Arial', 'B', 12) pdf.cell(50, 8, 'Hierarchical Network', 1, 0, 'C') pdf.ln(10) pdf.image(imagelist2[2], w=195, h=250) #Saving pdf pdf.output("./pdf/portfolio_analysis.pdf", "F")
def plate(request): try: o = Order.objects.filter(session=request.shop_session, is_history=True).latest('id') config, create = ConfigModel.objects.get_or_create(id=1) domain = Site.objects.get_current().domain except: pass else: if config.organization and config.office1 and o.address and o.name: pdf = FPDF('P', 'mm', 'A4') pdf.set_author(domain) pdf.add_page() pdf.add_font('DejaVu', '', 'DejaVuSansCondensed.ttf', uni=True) pdf.add_font('DejaVuBold', '', 'DejaVuSansCondensed-Bold.ttf', uni=True) pdf.set_fill_color(229, 229, 229) pdf.set_font('DejaVu', '', 5) pdf.write( 9, _(u"Created by %(date)s on %(domain)s. Order #%(id)d.") % { 'date': datetime.datetime.now().strftime('%d.%m.%Y %H:%M'), 'domain': domain, 'id': o.id }) pdf.ln(9) pdf.set_font('DejaVuBold', '', 9) pdf.write(9, _(u"Recipient:")) pdf.ln(9) pdf.set_font('DejaVu', '', 8) if config.office1: pdf.write(5, _(u"Address: %s") % config.office1) pdf.ln(5) if config.organization: pdf.write(5, _(u"Name: %s") % config.organization) pdf.ln(5) pdf.set_font('DejaVuBold', '', 9) pdf.write(9, _(u"Sender:")) pdf.ln(9) pdf.set_font('DejaVu', '', 8) if o.address: pdf.write(5, _(u"Address: %s") % o.address) pdf.ln(5) if o.name: pdf.write(5, _(u"Name: %s") % o.name) pdf.ln(9) pdf.set_font('DejaVu', '', 5) pdf.write(5, _(u"Cut and paste on the packaging")) pdf.ln(5) s = pdf.output('Plate.pdf', 'S') response = HttpResponse(s, mimetype='application/pdf; charset=cp1251') response['Content-Disposition'] = 'attachment; filename=plate.pdf' return response return HttpResponse('')
def save_history(request): stdate, spdate = None, None if 'stdate' in request.GET: stdate = datetime.datetime.strptime(request.GET.get('stdate'), '%d.%m.%Y') if 'spdate' in request.GET: spdate = datetime.datetime.strptime(request.GET.get('spdate'), '%d.%m.%Y') if stdate and spdate: o = Order.objects.filter(Q(date__gte=stdate) & Q(date__lte=spdate)).order_by('date') domain = Site.objects.get_current().domain def ImprovedTable(pdf, oo, data): header = [ _(u"#id"), _(u"Title"), _(u"Price"), _(u"Count"), _(u"Cost") ] w = [20, 70, 20, 20, 20] for i in range(len(header)): pdf.cell(w[i], 5, u'%s' % header[i], 1, 0, 'C', 1) pdf.ln() for row in data: pdf.cell(w[0], 5, u'%d' % row.product.id, 'LR') pdf.cell(w[1], 5, u'%s' % row.product.title, 'LR') pdf.cell(w[2], 5, u'%d' % row.get_cost(), 'LR', 0, 'R') pdf.cell(w[3], 5, u'%d' % row.count, 'LR', 0, 'R') pdf.cell(w[4], 5, u'%d' % row.get_total_cost(), 'LR', 0, 'R') pdf.ln() if oo.is_delivery: pdf.cell(w[0], 5, u'-', 'LR') pdf.cell(w[1], 5, _(u"Delivery"), 'LR') pdf.cell(w[2], 5, u'%d' % oo.cost_delivery, 'LR', 0, 'R') pdf.cell(w[3], 5, u'-', 'LR', 0, 'R') pdf.cell(w[4], 5, u'%d' % oo.cost_delivery, 'LR', 0, 'R') pdf.ln() pdf.cell(sum(w), 0, '', 'T') return pdf pdf = FPDF('P', 'mm', 'A4') pdf.set_author(domain) pdf.add_page() pdf.add_font('DejaVu', '', 'DejaVuSansCondensed.ttf', uni=True) pdf.add_font('DejaVuBold', '', 'DejaVuSansCondensed-Bold.ttf', uni=True) pdf.set_fill_color(229, 229, 229) pdf.set_font('DejaVu', '', 5) pdf.write( 5, _(u"History created at %s") % datetime.datetime.now().strftime('%d.%m.%Y %H:%M')) pdf.ln(5) pdf.set_font('DejaVuBold', '', 8) pdf.write(5, _(u"History")) pdf.ln(5) for x in o: op = x.get_op() if op.count(): pdf.set_font('DejaVuBold', '', 8) pdf.write( 5, u'Order #%d at %s on sum %d. Status: %s. Products:' % (x.id, x.date.strftime('%d.%m.%Y %H:%M'), x.get_total_cost(), x.status.title)) pdf.ln(5) pdf.set_font('DejaVu', '', 5) pdf = ImprovedTable(pdf, x, x.get_op()) pdf.ln(5) s = pdf.output('History.pdf', 'S') response = HttpResponse(s, mimetype='application/pdf; charset=cp1251') response['Content-Disposition'] = 'attachment; filename=History.pdf' return response return HttpResponse('')
class kut2fpdf(object): _document = None # Aquí se irán guardando los datos del documento logger = None _xml = None _xml_data = None _page_orientation = None _page_size = None _bottom_margin = None _left_margin = None _right_margin = None _top_margin = None _page_top = {} _data_row = None # Apunta a la fila actual en data _parser_tools = None _avalible_fonts = None _unavalible_fonts = None design_mode = None _actual_data_line = None _no_print_footer = False _actual_section_size = None increase_section_size = None last_detail = False actual_data_level = None last_data_processed = None prev_level = None draws_at_header = None detailn = None name_ = None _actual_append_page_no = None reset_page_count = None def __init__(self): self.logger = logging.getLogger("kut2fpdf") checkDependencies({"fpdf": "pyfpdf"}) from pineboolib.plugins.kugar.parsertools import parsertools self._parser_tools = parsertools() self._avalible_fonts = [] self._unavalible_fonts = [] self.design_mode = FLSettings().readBoolEntry("ebcomportamiento/kugar_debug_mode") self._actual_data_line = None self._no_print_footer = False self.increase_section_size = 0 self.actual_data_level = 0 self.prev_level = -1 self.draws_at_header = {} self.detailn = {} self.name_ = None self._actual_append_page_no = 0 self.reset_page_count = False self.new_page = False """ Convierte una cadena de texto que contiene el ".kut" en un pdf y retorna la ruta a este último. @param name. Nombre de ".kut". @param kut. Cadena de texto que contiene el ".kut". @param data. Cadena de texto que contiene los datos para ser rellenados en el informe. @return Ruta a fichero pdf. """ def parse(self, name, kut, data, report = None, flags = []): try: self._xml = self._parser_tools.loadKut(kut) except Exception: self.logger.exception( "KUT2FPDF: Problema al procesar %s.kut", name) return False try: self._xml_data = load2xml(data) except Exception: self.logger.exception("KUT2FPDF: Problema al procesar xml_data") return False self.name_ = name self.setPageFormat(self._xml) # self._page_orientation = # self._page_size = if report is None: from fpdf import FPDF self._actual_append_page_no = -1 self._document = FPDF(self._page_orientation, "pt", self._page_size) for f in self._document.core_fonts: self.logger.debug("KUT2FPDF :: Adding font %s", f) self._avalible_fonts.append(f) else: self._document = report # Seteamos rutas a carpetas con tipos de letra ... # Cargamos las fuentes disponibles next_page_break = (flags[2] == 1) if len(flags) == 3 else True page_append = (flags[1] == 1) if len(flags) > 1 else False page_display = (flags[0] == 1) if len(flags) > 0 else False if page_append: self.prev_level = -1 self.last_detail = False page_break = False if self.new_page: page_break = True self.new_page = False if self.reset_page_count: self.reset_page_no() self.reset_page_count = False if self.design_mode: print("Append", page_append) print("Display", page_display) print("Page break", next_page_break) if next_page_break: self.reset_page_count = True if page_display: self.new_page = True self.processDetails(not page_break) #FIXME:Alguno valores no se encuentran for p in self._document.pages.keys(): page_content = self._document.pages[p]["content"] for h in self.draws_at_header.keys(): page_content = page_content.replace(h, str(self.draws_at_header[h])) self._document.pages[p]["content"] = page_content #print(self.draws_at_header.keys()) self._document.set_title(self.name_) self._document.set_author("Pineboo - kut2fpdf plugin") return self._document def get_file_name(self): import os pdf_name = aqApp.tmp_dir() pdf_name += "/%s_%s.pdf" % (self.name_, datetime.datetime.now().strftime("%Y%m%d%H%M%S")) if os.path.exists(pdf_name): os.remove(pdf_name) if self._document is not None: self._document.output(pdf_name, 'F') return pdf_name else: return None """ Indica el techo para calcular la posición de los objetos de esa sección. @return Número con el techo de la página actual. """ def topSection(self): return self._page_top[str(self._document.page_no())] """ Actualiza el valor del techo de la página actual. Se suele actualizar al procesar una sección. @param value. Numero que elspecifica el nuevo techo. """ def setTopSection(self, value): self._actual_section_size = value - self.topSection() self._page_top[str(self._document.page_no())] = value """ Añade una nueva página al documento. """ def newPage(self, data_level, add_on_header = True): self._document.add_page(self._page_orientation) self._page_top[str(self._document.page_no())] = self._top_margin self._document.set_margins(self._left_margin, self._top_margin, self._right_margin) # Lo dejo pero no se nota nada self._no_print_footer = False if self.design_mode: self.draw_margins() self._actual_section_size = 0 self._actual_append_page_no += 1 if self.design_mode: print("Nueva página", self.number_pages()) #l_ini = data_level #l_end = self.prev_level #if l_ini == l_end: # l_end = l_end + 1 #if l_ini <= l_end: # for l in range(l_ini , l_end): # print(l) # self.processSection("AddOnHeader", str(l)) pg_headers = self._xml.findall("PageHeader") for ph in pg_headers: if self.number_pages() == 0 or ph.get("PrintFrequency") == "1": ph_level = ph.get("Level") if ph.get("Level") is not None else None self.processSection("PageHeader", ph_level) break if add_on_header and not self.number_pages() == 0: for l in range(data_level + 1): self.processSection("AddOnHeader", str(l)) #Por ahora se omite detail header """ Procesa las secciones details con sus correspondientes detailHeader y detailFooter. """ def processDetails(self, keep_page = None): # Procesamos la cabecera si procede .. top_level = 0 level = 0 first_page_created = keep_page if keep_page is not None and self._document.page_no() > 0 else False rows_array = self._xml_data.findall("Row") for data in rows_array: self._actual_data_line = data level = int(data.get("level")) if level > top_level: top_level = level if not first_page_created: self.newPage(level) first_page_created = True if rows_array[len(rows_array) - 1] is data: self.last_detail = True if level < self.prev_level: for l in range(level + 1, self.prev_level + 1): self.processData("DetailFooter", self.last_data_processed, l) if not str(level) in self.detailn.keys(): self.detailn[str(level)] = 0 else: self.detailn[str(level)] += 1 if level > self.prev_level: self.processData("DetailHeader", data, level) self.processData("Detail", data, level) self.last_data_processed = data self.prev_level = level if not self._no_print_footer: for l in reversed(range(top_level + 1)): self.processData("DetailFooter", data, l) """ Paso intermedio que calcula si detailHeader + detail + detailFooter entran en el resto de la ṕagina. Si no es así crea nueva página. @param section_name. Nombre de la sección a procesar. @param data. Linea de datos a procesar. @param data_level. Nivel de seccion. """ def processData(self, section_name, data, data_level): self.actual_data_level = data_level listDF = self._xml.findall(section_name) data_size = len(listDF) for dF in listDF: draw_if = dF.get("DrawIf") show = True if draw_if: show = data.get(draw_if) if dF.get("Level") == str(data_level) and show not in ("None", "False"): if section_name in ("DetailHeader","Detail"): heightCalculated = self._parser_tools.getHeight(dF) + self.topSection() if section_name is "DetailHeader": for detail in self._xml.findall("Detail"): if detail.get("Level") == str(data_level): heightCalculated += self._parser_tools.getHeight(detail) for dFooter in self._xml.findall("DetailFooter"): if dFooter.get("Level") == str(data_level): heightCalculated += self._parser_tools.getHeight(dFooter) #for addFooter in self._xml.findall("AddOnFooter"): # if addFooter.get("Level") == str(data_level): # heightCalculated += self._parser_tools.getHeight(addFooter) pageFooter = self._xml.get("PageFooter") if pageFooter: if self._document.page_no() == 1 or pageFooter.get("PrintFrecuency") == "1": heightCalculated += self._parser_tools.getHeight(pageFooter) heightCalculated += self._bottom_margin if heightCalculated > self._document.h: # Si nos pasamos self._no_print_footer = True #Vemos el tope por abajo limit_bottom = self._document.h - self._parser_tools.getHeight(self._xml.get("AddOnFooter")) actual_size = self._parser_tools.getHeight(dF) + self.topSection() if (actual_size > limit_bottom + 2) or self.last_detail: # +2 se usa de margen extra self.processSection("AddOnFooter", str(data_level)) self.newPage(data_level) self.processXML(dF, data) if dF.get("NewPage") == "true" and not self.last_detail: self.newPage(data_level, False) break #Se ejecuta una sola instancia """ Procesa las secciones fuera de detail @param name. Nombre de la sección a procesar. """ def processSection(self, name, level=0): sec_list = self._xml.findall(name) sec_ = None for s in sec_list: if s.get("Level") == str(level) or s.get("Level") is None: sec_ = s if sec_ is not None: if sec_.get("PrintFrequency") == "1" or self._document.page_no() == 1 or name in ("AddOnHeader","AddOnFooter"): self.processXML(sec_) """ Procesa un elemento de xml. @param xml: El elemento a procesar. @param. data: Linea de datos afectada. """ def processXML(self, xml, data=None): fix_height = True if data is None: data = self._actual_data_line if self.design_mode: print("Procesando", xml.tag, data.get("level")) size_updated = False if xml.tag == "DetailFooter": if xml.get("PlaceAtBottom") == "true": self.setTopSection(self._document.h - self._parser_tools.getHeight(xml)) size_updated = True if xml.tag == "PageFooter": fix_height = False self.fix_extra_size() #Sirve para actualizar la altura con lineas que se han partido porque son muy largas for label in xml.iter("Label"): self.processText(label, data, fix_height) for field in xml.iter("Field"): self.processText(field, data, fix_height) for special in xml.iter("Special"): self.processText(special, data, fix_height, xml.tag) for calculated in xml.iter("CalculatedField"): self.processText(calculated, data, fix_height, xml.tag) #Busco draw_at_header en DetailFooter y los meto también if xml.tag == "DetailHeader": detail_level = xml.get("Level") for df in self._xml.iter("DetailFooter"): if df.get("Level") == detail_level: for cf in df.iter("CalculatedField"): if cf.get("DrawAtHeader") == "true": header_name = "%s_header_%s_%s" % (self.detailn[detail_level], detail_level, cf.get("Field")) self.draws_at_header[header_name] = "" self.processText(cf, data, fix_height, xml.tag) for line in xml.iter("Line"): self.processLine(line, fix_height) if not size_updated: self.setTopSection(self.topSection() + self._parser_tools.getHeight(xml)) def fix_extra_size(self): if self.increase_section_size > 0: self.setTopSection(self.topSection() + self.increase_section_size) self.increase_section_size = 0 """ Procesa una linea. @param xml. Sección de xml a procesar. @param fix_height. Ajusta la altura a los .kut originales, excepto el pageFooter. """ def processLine(self, xml, fix_height=True): color = xml.get("Color") r = 0 if not color else int(color.split(",")[0]) g = 0 if not color else int(color.split(",")[1]) b = 0 if not color else int(color.split(",")[2]) style = int(xml.get("Style")) width = int(xml.get("Width")) X1 = self.calculateLeftStart(xml.get("X1")) X1 = self.calculateWidth(X1, 0, False) X2 = self.calculateLeftStart(xml.get("X2")) X2 = self.calculateWidth(X2, 0, False) # Ajustar altura a secciones ya creadas Y1 = int(xml.get("Y1")) + self.topSection() Y2 = int(xml.get("Y2")) + self.topSection() if fix_height: Y1 = self._parser_tools.ratio_correction(Y1) Y2 = self._parser_tools.ratio_correction(Y2) self._document.set_line_width(width) self._document.set_draw_color(r, g, b) dash_length = 1 space_length = 1 if style == 2: dash_length = 20 space_length = 20 elif style == 3: dash_length = 10 space_length = 10 self._document.dashed_line(X1, Y1, X2, Y2, dash_length, space_length) #else: # self._document.line(X1, Y1, X2, Y2) """ Comprueba si excedemos el margen izquierdo de la página actual @param x. Posición a comprobar. @return Valor corregido, si procede. """ def calculateLeftStart(self, x): return self._parser_tools.ratio_correction(int(x)) + self._left_margin """ Comprueba si excedemos el margen derecho de la página actual @param x. Posición a comprobar. @return Valor corregido, si procede. """ def calculateWidth(self, width, pos_x, fix_ratio = True): width = int(width) if fix_ratio: width = self._parser_tools.ratio_correction(int(width)) ret_ = width limit = self._document.w - self._right_margin if pos_x + width > limit: ret_ = limit - pos_x return ret_ """ Procesa una etiqueta. Esta puede ser un campo calculado, una etiqueta, un campo especial o una imagen. @param xml. Sección de xml a procesar. @param fix_height. Ajusta la altura a los .kut originales, excepto el pageFooter. """ def processText(self, xml, data_row=None, fix_height=True, section_name = None): is_image = False is_barcode = False text = xml.get("Text") borderColor = xml.get("BorderColor") field_name = xml.get("Field") # x,y,W,H se calcula y corrigen aquí para luego estar correctos en los diferentes destinos posibles W = int(xml.get("Width")) H = self._parser_tools.getHeight(xml) x = int(xml.get("X")) y = int(xml.get("Y")) + self.topSection() # Añade la altura que hay ocupada por otras secciones if fix_height: y = self._parser_tools.ratio_correction(y) # Corrige la posición con respecto al kut original data_type = xml.get("DataType") if xml.tag == "Field" and data_row is not None: text = data_row.get(field_name) elif xml.tag == "Special": if text == "": if xml.get("Type") == "1": text = "PageNo" text = self._parser_tools.getSpecial( text, self._actual_append_page_no) calculation_type = xml.get("CalculationType") if calculation_type is not None and xml.tag != "Field": if calculation_type == "6": function_name = xml.get("FunctionName") try: nodo = self._parser_tools.convertToNode(data_row) from pineboolib.pncontrolsfactory import aqApp ret_ = aqApp.call(function_name, [nodo, field_name]) if ret_ is False: return else: text = str(ret_) except Exception: self.logger.exception( "KUT2FPDF:: Error llamando a function %s", function_name) return elif calculation_type == "1": text = self._parser_tools.calculate_sum(field_name, self.last_data_processed, self._xml_data, self.actual_data_level) elif calculation_type in ("5"): if data_row is None: data_row = self._xml_data[0] text = data_row.get(field_name) if data_type is not None: text = self._parser_tools.calculated(text, int(data_type), xml.get("Precision"), data_row) if data_type == "5": is_image = True elif data_type == "6": is_barcode = True if xml.get("BlankZero") == "1" and text is not None: res_ = re.findall(r'\d+', text) res_ = "".join(res_) if int(res_) == 0: return if text is not None and text.startswith(filedir("../tempdata")): is_image = True negValueColor = xml.get("NegValueColor") Currency = xml.get("Currency") commaSeparator = xml.get("CommaSeparator") dateFormat = xml.get("DateFormat") if is_image: self.draw_image(x, y, W, H, xml, text) elif is_barcode: self.draw_barcode(x, y, W, H, xml, text) else: level = data_row.get("level") if level and str(level) in self.detailn.keys(): val = "%s_header_%s_%s" % ( self.detailn[str(level)], level,field_name) if xml.get("DrawAtHeader") == "true" and level: if section_name == "DetailHeader": val = "" self.drawText(x, y, W, H, xml, val) print(level, section_name, val, text) if section_name == "DetailFooter" and xml.get("DrawAtHeader") == "true": self.draws_at_header[val] = text print("Añadiendo a", val, text, level) else: self.drawText(x, y, W, H, xml, text) """ Dibuja un campo texto en la página. @param x. Pos x de la etiqueta. @param y. Pos y de la etiqueta. @param W. Anchura de la etiqueta. @param H. Altura de la etiqueta. @param xml. Sección del xml afectada. @param txt. Texto calculado de la etiqueta a crear. """ def drawText(self, x, y, W, H, xml, txt): if txt in ("None", None): return txt = self._parser_tools.restore_text(txt) resizeable = False if xml.get("ChangeHeight") == "1": resizeable = True height_resized = False orig_x = x orig_y = y orig_W = W orig_H = H # Corregimos margenes: x = self.calculateLeftStart(x) W = self.calculateWidth(W, x) #bg_color = xml.get("BackgroundColor").split(",") fg_color = self.get_color(xml.get("ForegroundColor")) self._document.set_text_color(fg_color[0], fg_color[1], fg_color[2]) #self._document.set_draw_color(255, 255, 255) #if xml.get("BorderStyle") == "1": # FIXME: Hay que ajustar los margenes #font_name, font_size, font_style font_style = "" font_size = int(xml.get("FontSize")) font_name_orig = xml.get("FontFamily").lower() if xml.get("FontFamily") is not None else "helvetica" font_name = font_name_orig font_w = xml.get("FontWeight") if font_w in (None, "50"): #Normal font_w = 100 elif int(font_w) >= 65: font_style += "B" font_w = 100 fontI = xml.get("FontItalic") fontU = xml.get("FontUnderlined") # FIXME: hay que ver si es así background_color = self.get_color(xml.get("BackgroundColor")) #if background_color != [255,255,255]: #Los textos que llevan fondo no blanco van en negrita # font_style += "B" if fontI == "1": font_style += "I" if fontU == "1": font_style += "U" font_full_name = "%s%s" % (font_name, font_style) if font_full_name not in self._avalible_fonts: font_found = self._parser_tools.find_font(font_full_name) if font_found: self.logger.warning("KUT2FPDF::Añadiendo el tipo de letra %s (%s)", font_full_name, font_found) self._document.add_font(font_full_name, "", font_found, True) self._avalible_fonts.append(font_full_name) else: if font_full_name not in self._unavalible_fonts: self.logger.warning("KUT2FPDF:: No se encuentra el tipo de letra %s. Sustituido por helvetica%s." %(font_full_name, font_style)) self._unavalible_fonts.append(font_full_name) font_name = "helvetica" if font_name is not font_name_orig and font_name_orig.lower().find("narrow") > -1: font_w = 85 self._document.set_font(font_name, font_style, font_size) self._document.set_stretching(font_w) # Corregir alineación VAlignment = xml.get("VAlignment") # 0 izquierda, 1 centrado,2 derecha HAlignment = xml.get("HAlignment") layout_direction = xml.get("layoutDirection") start_section_size = self._actual_section_size result_section_size = 0 #Miramos si el texto sobrepasa el ancho array_text = [] array_n = [] text_lines = [] if txt.find("\n") > -1: for t in txt.split("\n"): array_n.append(t) if array_n: #Hay saltos de lineas ... for n in array_n: text_lines.append(n) else: #No hay saltos de lineas text_lines.append(txt) for tl in text_lines: str_width = self._document.get_string_width(tl) if str_width > W + 2 and xml.tag !="Label" and resizeable: #Una linea es mas larga que el ancho del campo(Dejando 2 de juego) height_resized = True array_text = self.split_text(tl, W) else: array_text.append(tl) #calculated_h = orig_H * len(array_text) self.drawRect(orig_x, orig_y, orig_W, orig_H, xml) processed_lines = 0 extra_size = 0 for actual_text in array_text: if actual_text is None: continue processed_lines += 1 if processed_lines > 1: extra_size += font_size + 2 if HAlignment == "1": # sobre X # Centrado x = x + (W / 2) - (self._document.get_string_width(actual_text) / 2) #x = x + (W / 2) - (str_width if not height_resized else W / 2) elif HAlignment == "2": # Derecha x = x + W - self._document.get_string_width(actual_text) - 2 # -2 de margen #x = x + W - str_width if not height_resized else W else: # Izquierda x = x + 2 if VAlignment == "1": # sobre Y # Centrado #y = (y + ((H / 2) / processed_lines)) + (((self._document.font_size_pt / 2) / 2) * processed_lines) y = ( orig_y + ( orig_H / 2))+ ((self._document.font_size_pt / 2) /2) elif VAlignment == "2": # Abajo y = orig_y + orig_H - font_size else: # Arriba y = orig_y + font_size y = y + extra_size if self.design_mode: self.write_debug(self.calculateLeftStart(orig_x), y, "Hal:%s, Val:%s, T:%s st:%s" % (HAlignment, VAlignment, txt, font_w), 6, "green") if xml.tag == "CalculatedField": self.write_debug(self.calculateLeftStart(orig_x), y, "CalculatedField:%s, Field:%s" % (xml.get("FunctionName"), xml.get("Field")), 3, "blue") self._document.text(x, y, actual_text) result_section_size += start_section_size result_section_size = result_section_size - start_section_size if self.increase_section_size < extra_size: #Si algun incremento extra hay superior se respeta self.increase_section_size = extra_size def split_text(self, texto, limit_w): list_ = [] linea_ = None for t in texto.split(" "): if linea_ is None and t == "": continue if linea_ is not None: if self._document.get_string_width(linea_ + t) > limit_w: list_.append(linea_) linea_ = "" else: linea_ = "" linea_ += "%s " % t list_.append(linea_) return list_ """ Dibuja un cuadrado en la página actual. @param x. Pos x del cuadrado. @param y. Pos y del cuadrado. @param W. Anchura del cuadrado. @param H. Altura del cuadrado. """ def get_color(self, value): value = value.split(",") r = None g = None b = None if len(value) == 3: r = int(value[0]) g = int(value[1]) b = int(value[2]) else: r = int(value[0:2]) g = int(value[3:5]) b = int(value[6:8]) return [r,g,b] def drawRect(self, x, y, W, H, xml = None): style_ = "" border_color = None bg_color = None line_width = self._document.line_width border_width = 0.2 #Calculamos borde y restamos del ancho orig_x = x orig_y = y orig_w = W x = self.calculateLeftStart(orig_x) W = self.calculateWidth(W, x) if xml is not None and not self.design_mode: if xml.get("BorderStyle") == "1": border_color = self.get_color(xml.get("BorderColor")) self._document.set_draw_color(border_color[0], border_color[1], border_color[2]) style_ += "D" bg_color = self.get_color(xml.get("BackgroundColor")) self._document.set_fill_color(bg_color[0], bg_color[1], bg_color[2]) style_ = "F" + style_ border_width = int(xml.get("BorderWidth") if xml.get("BorderWidth") else 0.2) else: self.write_cords_debug(x,y,W,H, orig_x, orig_w) style_ = "D" self._document.set_draw_color(0, 0, 0) if style_ is not "": self._document.set_line_width(border_width) self._document.rect(x, y, W, H, style_) self._document.set_line_width(line_width) self._document.set_xy(orig_x, orig_y) #self._document.set_draw_color(255, 255, 255) #self._document.set_fill_color(0, 0, 0) def write_cords_debug(self, x, y, w, h, ox, ow): self.write_debug(x,y,"X:%s Y:%s W:%s H:%s orig_x:%s, orig_W:%s" % (round(x, 2),round(y, 2),round(w, 2),round(h, 2), round(ox, 2), round(ow, 2)), 2, "red") def write_debug(self, x,y,text, h, color = None): orig_color = self._document.text_color r = None g = None b = None current_font_family = self._document.font_family current_font_size = self._document.font_size_pt current_font_style = self._document.font_style if color is "red": r = 255 g = 0 b = 0 elif color is "green": r = 0 g = 255 b = 0 elif color is "blue": r = 0 g = 0 b = 255 self._document.set_text_color(r,g,b) self._document.set_font_size(4) self._document.text(x, y + h, text) self._document.text_color = orig_color #self._document.set_xy(orig_x, orig_y) self._document.set_font(current_font_family, current_font_style, current_font_size) """ Inserta una imagen en la página actual. @param x. Pos x de la imagen. @param y. Pos y de la imagen. @param W. Anchura de la imagen. @param H. Altura de la imagen. @param xml. Sección del xml afectada. @param file_name. Nombr del fichero de tempdata a usar """ def draw_image(self, x, y, W, H, xml, file_name): import os if not file_name.lower().endswith(".png"): file_name = self._parser_tools.parseKey(file_name) if file_name is not None and os.path.exists(file_name): x = self.calculateLeftStart(x) W = self.calculateWidth(W, x) self._document.image(file_name, x, y, W, H, "PNG") def draw_barcode(self, x, y, W, H, xml, text): if text == "None": return from pineboolib.fllegacy.flcodbar import FLCodBar file_name = aqApp.tmp_dir() file_name += "/%s.png" % (text) type = xml.get("CodBarType") if not os.path.exists(file_name): bar_code = FLCodBar(text) #Code128 if type is not None: type = bar_code.nameToType(type.lower()) bar_code.setType(type) pix = bar_code.pixmap() if not pix.isNull(): pix.save(file_name, "PNG") self.draw_image(x , y, W, H, xml, file_name) """ Define los parámetros de la página @param xml: Elemento xml con los datos del fichero .kut a procesar """ def setPageFormat(self, xml): custom_size = None self._bottom_margin = int(xml.get("BottomMargin")) self._left_margin = int(xml.get("LeftMargin")) self._right_margin = int(xml.get("RightMargin")) self._top_margin = int(xml.get("TopMargin")) page_size = int(xml.get("PageSize")) page_orientation = xml.get("PageOrientation") if page_size in [30, 31]: custom_size = [int(xml.get("CustomHeightMM")), int(xml.get("CustomWidthMM"))] self._page_orientation = "P" if page_orientation == "0" else "L" self._page_size = self._parser_tools.converPageSize( page_size, int(page_orientation), custom_size) # devuelve un array def draw_margins(self): self.draw_debug_line(0 + self._left_margin , 0, 0+ self._left_margin , self._page_size[1]) #Vertical derecha self.draw_debug_line(self._page_size[0] - self._right_margin , 0, self._page_size[0] - self._right_margin , self._page_size[1])#Vertical izquierda self.draw_debug_line(0, 0 + self._top_margin, self._page_size[0], 0 + self._top_margin) #Horizontal superior self.draw_debug_line(0, self._page_size[1] - self._bottom_margin, self._page_size[0], self._page_size[1] - self._bottom_margin) #Horizontal inferior def draw_debug_line(self, X1, Y1, X2, Y2, title= None, color="GREY"): dash_length = 2 space_length = 2 r = 0 g = 0 b = 0 if color == "GREY": r = 220 g = 220 b = 220 self._document.set_line_width(1) self._document.set_draw_color(r, g, b) self._document.dashed_line(X1, Y1, X2, Y2, dash_length, space_length) def number_pages(self): return self._actual_append_page_no if self._actual_append_page_no > 0 else 0 def reset_page_no(self): self._actual_append_page_no = -1
def create_report(resource): pdf = FPDF(orientation='P', format='A4') try: pdf.add_font('Montserrat', '', os.path.join(os.path.expanduser('~'), '.sms/Montserrat-Regular.ttf'), uni=True) pdf.add_font('Montserrat', 'B', os.path.join(os.path.expanduser('~'), '.sms/Montserrat-Bold.ttf'), uni=True) font_style = 'Montserrat' except: font_style = 'Arial' g = core.Get() if resource == 'Summary': pdf.add_page() pdf.set_author('SMS') pdf.set_font(font_style, 'B', 10) pdf.cell(0, txt='System Monitoring System', ln=1, align='C') pdf.set_font(font_style, 'B', 32) pdf.cell(0, h=25, txt='Report', ln=1, align='C') pdf.set_font(font_style, 'B', 20) pdf.cell(0, h=15, txt='Overall Usage Summary - ', ln=1) pdf.set_font(font_style, '', 12) text = 'OS: {}'.format(g.os()) pdf.cell(0, h=5, txt=text, ln=1) text = 'Uptime: {} seconds'.format(g.uptime()) pdf.cell(0, h=5, txt=text, ln=1) pdf.ln() # CPU data pdf.set_font(font_style, 'B', 16) pdf.cell(0, h=15, txt='CPU:-', ln=1) pdf.set_font(font_style, '', 12) cpu_dict = g.cpu() if os.name != 'nt': text = 'Load Average: {} {} {}'.format(cpu_dict['load_avg'][0], cpu_dict['load_avg'][1], cpu_dict['load_avg'][2]) pdf.cell(0, h=5, txt=text, ln=1) text = 'User: {} %'.format(cpu_dict['user']) pdf.cell(0, h=5, txt=text, ln=1) text = 'System: {} %'.format(cpu_dict['system']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Idle: {} %'.format(cpu_dict['idle']) pdf.cell(0, h=5, txt=text, ln=1) if os.name != 'nt': text = 'I/O Wait: {} %'.format(cpu_dict['iowait']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Cores: {}'.format(cpu_dict['num_cores']) pdf.cell(0, h=5, txt=text, ln=1) pdf.ln() # Memory data pdf.set_font(font_style, 'B', 16) pdf.cell(0, h=15, txt='Memory:-', ln=1) pdf.set_font(font_style, '', 12) memory_dict = g.memory() text = 'Total: {:,} Bytes'.format(memory_dict['total']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Used: {:,} Bytes'.format(memory_dict['used_incl']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Free: {:,} Bytes'.format(memory_dict['free']) pdf.cell(0, h=5, txt=text, ln=1) pdf.ln() # Network data pdf.set_font(font_style, 'B', 16) pdf.cell(0, h=15, txt='Network:-', ln=1) pdf.set_font(font_style, '', 12) networks = g.network() for network_dict in networks: text = 'Interface: {}'.format(network_dict['interface']) pdf.cell(0, h=5, txt=text, ln=1) if os.name != 'nt': text = 'IP: {}'.format(network_dict['ip']) pdf.cell(0, h=5, txt=text, ln=1) pdf.ln() # Storage data pdf.set_font(font_style, 'B', 16) pdf.cell(0, h=15, txt='Storage:-', ln=1) pdf.set_font(font_style, '', 12) storages = g.storage() for storage_dict in storages: text = 'Device: {}'.format(storage_dict['device']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Mounted: {}'.format(storage_dict['mountpoint']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Total: {:,} Bytes'.format(storage_dict['total']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Used: {:,} Bytes ({}%)'.format(storage_dict['used'], storage_dict['percent']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Free: {:,} Bytes'.format(storage_dict['free']) pdf.cell(0, h=5, txt=text, ln=1) pdf.ln() # Swap data pdf.set_font(font_style, 'B', 16) pdf.cell(0, h=15, txt='Swap:-', ln=1) pdf.set_font(font_style, '', 12) swap_dict = g.swap() text = 'Total: {:,} Bytes'.format(swap_dict['total']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Used: {:,} Bytes ({}%)'.format(swap_dict['used'], swap_dict['percent']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Free: {:,} Bytes'.format(swap_dict['free']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Swapped in: {:,} Bytes'.format(swap_dict['sin']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Swapped out: {:,} Bytes'.format(swap_dict['sout']) pdf.cell(0, h=5, txt=text, ln=1) pdf.ln() # Users data pdf.set_font(font_style, 'B', 16) pdf.cell(0, h=15, txt='Users:-', ln=1) pdf.set_font(font_style, '', 12) users = g.users() for user_dict in users: text = 'Name: {}'.format(user_dict['name']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Session started: {}'.format(user_dict['sess_started']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Host: {}'.format(user_dict['host']) pdf.cell(0, h=5, txt=text, ln=1) pdf.ln() elif resource == 'CPU': pdf.add_page() pdf.set_author('SMS') pdf.set_font(font_style, 'B', 10) pdf.cell(0, txt='System Monitoring System', ln=1, align='C') pdf.set_font(font_style, 'B', 32) pdf.cell(0, h=25, txt='Report', ln=1, align='C') pdf.set_font(font_style, 'B', 20) pdf.cell(0, h=15, txt='CPU Usage Summary - ', ln=1) pdf.set_font(font_style, 'B', 16) pdf.cell(0, h=15, txt='Overall:-', ln=1) pdf.set_font(font_style, '', 12) cpu_dict = g.cpu() if os.name != 'nt': text = 'Load Average: {} {} {}'.format(cpu_dict['load_avg'][0], cpu_dict['load_avg'][1], cpu_dict['load_avg'][2]) pdf.cell(0, h=5, txt=text, ln=1) text = 'User: {} %'.format(cpu_dict['user']) pdf.cell(0, h=5, txt=text, ln=1) text = 'System: {} %'.format(cpu_dict['system']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Idle: {} %'.format(cpu_dict['idle']) pdf.cell(0, h=5, txt=text, ln=1) text = 'I/O Wait: {} %'.format(cpu_dict['iowait']) pdf.cell(0, h=5, txt=text, ln=1) counter = 1 for cpu_core in cpu_dict['cores']: pdf.ln() pdf.set_font(font_style, 'B', 16) text = 'Core {}:-'.format(counter) pdf.cell(0, h=15, txt=text, ln=1) pdf.set_font(font_style, '', 12) text = 'User: {} %'.format(cpu_core['user']) pdf.cell(0, h=5, txt=text, ln=1) text = 'System: {} %'.format(cpu_core['system']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Idle: {} %'.format(cpu_core['idle']) pdf.cell(0, h=5, txt=text, ln=1) if os.name != 'nt': text = 'I/O Wait: {} %'.format(cpu_core['iowait']) pdf.cell(0, h=5, txt=text, ln=1) counter += 1 elif resource == 'Memory': pdf.add_page() pdf.set_author('SMS') pdf.set_font(font_style, 'B', 10) pdf.cell(0, txt='System Monitoring System', ln=1, align='C') pdf.set_font(font_style, 'B', 32) pdf.cell(0, h=25, txt='Report', ln=1, align='C') pdf.set_font(font_style, 'B', 20) pdf.cell(0, h=15, txt='Memory Usage Summary - ', ln=1) pdf.set_font(font_style, '', 12) memory_dict = g.memory() text = 'Total: {:,} Bytes'.format(memory_dict['total']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Available: {:,} Bytes'.format(memory_dict['available']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Used (excl. Cache & buffer): {:,} Bytes ({}%)'.format( memory_dict['used_excl'], memory_dict['percent']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Used (incl. Cache & buffer): {:,} Bytes'.format( memory_dict['used_incl']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Free: {:,} Bytes'.format(memory_dict['free']) pdf.cell(0, h=5, txt=text, ln=1) elif resource == 'Network': pdf.add_page() pdf.set_author('SMS') pdf.set_font(font_style, 'B', 10) pdf.cell(0, txt='System Monitoring System', ln=1, align='C') pdf.set_font(font_style, 'B', 32) pdf.cell(0, h=25, txt='Report', ln=1, align='C') pdf.set_font(font_style, 'B', 20) pdf.cell(0, h=15, txt='Network Usage Summary - ', ln=1) pdf.set_font(font_style, '', 12) networks = g.network() for network_dict in networks: text = 'Interface: {}'.format(network_dict['interface']) pdf.cell(0, h=5, txt=text, ln=1) if os.name != 'nt': text = 'IP: {}'.format(network_dict['ip']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Bytes sent: {}'.format(network_dict['bytes_sent']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Bytes received: {}'.format(network_dict['bytes_recv']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Packets sent: {}'.format(network_dict['packets_sent']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Packets received: {}'.format(network_dict['packets_recv']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Errors in: {}'.format(network_dict['errin']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Errors out: {}'.format(network_dict['errout']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Dropped in: {}'.format(network_dict['dropin']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Dropped out: {}'.format(network_dict['dropout']) pdf.cell(0, h=5, txt=text, ln=1) pdf.ln() speed_dict = core.test_speed() text = 'Download speed: {}'.format(speed_dict['down_speed']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Upload speed: {}'.format(speed_dict['up_speed']) pdf.cell(0, h=5, txt=text, ln=1) elif resource == 'Storage': pdf.add_page() pdf.set_author('SMS') pdf.set_font(font_style, 'B', 10) pdf.cell(0, txt='System Monitoring System', ln=1, align='C') pdf.set_font(font_style, 'B', 32) pdf.cell(0, h=25, txt='Report', ln=1, align='C') pdf.set_font(font_style, 'B', 20) pdf.cell(0, h=15, txt='Storage Usage Summary - ', ln=1) pdf.set_font(font_style, '', 12) storages = g.storage() for storage_dict in storages: text = 'Device: {}'.format(storage_dict['device']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Mounted: {}'.format(storage_dict['mountpoint']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Type: {}'.format(storage_dict['fstype']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Options: {}'.format(storage_dict['options']) pdf.multi_cell(0, h=5, txt=text) text = 'Total: {:,} Bytes'.format(storage_dict['total']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Used: {:,} Bytes ({}%)'.format(storage_dict['used'], storage_dict['percent']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Free: {:,} Bytes'.format(storage_dict['free']) pdf.cell(0, h=5, txt=text, ln=1) pdf.ln() elif resource == 'Process': pdf.add_page() pdf.set_author('SMS') pdf.set_font(font_style, 'B', 10) pdf.cell(0, txt='System Monitoring System', ln=1, align='C') pdf.set_font(font_style, 'B', 32) pdf.cell(0, h=25, txt='Report', ln=1, align='C') pdf.set_font(font_style, 'B', 20) pdf.cell(0, h=15, txt='Process Usage Summary - ', ln=1) pdf.set_font(font_style, '', 12) processes = g.process() for process_dict in processes: text = 'PID: {}'.format(process_dict['pid']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Name: {}'.format(process_dict['name']) pdf.cell(0, h=5, txt=text, ln=1) text = 'User: {}'.format(process_dict['user']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Status: {}'.format(process_dict['status']) pdf.multi_cell(0, h=5, txt=text) text = 'Created: {} seconds since the epoch'.format( process_dict['created']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Memory: {} %'.format(process_dict['memory']) pdf.cell(0, h=5, txt=text, ln=1) text = 'CPU: {} %'.format(process_dict['cpu']) pdf.cell(0, h=5, txt=text, ln=1) pdf.ln() elif resource == 'Miscellaneous': pdf.add_page() pdf.set_author('SMS') pdf.set_font(font_style, 'B', 10) pdf.cell(0, txt='System Monitoring System', ln=1, align='C') pdf.set_font(font_style, 'B', 32) pdf.cell(0, h=25, txt='Report', ln=1, align='C') pdf.set_font(font_style, 'B', 20) pdf.cell(0, h=15, txt='Miscellaneous Usage Summary - ', ln=1) pdf.set_font(font_style, '', 12) text = 'OS: {}'.format(g.os()) pdf.cell(0, h=5, txt=text, ln=1) text = 'Uptime: {} seconds'.format(g.uptime()) pdf.cell(0, h=5, txt=text, ln=1) pdf.ln() pdf.set_font(font_style, 'B', 16) pdf.cell(0, h=15, txt='Users:-', ln=1) pdf.set_font(font_style, '', 12) users = g.users() for user_dict in users: text = 'Name: {}'.format(user_dict['name']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Session started: {}'.format(user_dict['sess_started']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Host: {}'.format(user_dict['host']) pdf.cell(0, h=5, txt=text, ln=1) pdf.ln() pdf.set_font(font_style, 'B', 16) pdf.cell(0, h=15, txt='Swap:-', ln=1) pdf.set_font(font_style, '', 12) swap_dict = g.swap() text = 'Total: {:,} Bytes'.format(swap_dict['total']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Used: {:,} Bytes ({}%)'.format(swap_dict['used'], swap_dict['percent']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Free: {:,} Bytes'.format(swap_dict['free']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Swapped in: {:,} Bytes'.format(swap_dict['sin']) pdf.cell(0, h=5, txt=text, ln=1) text = 'Swapped out: {:,} Bytes'.format(swap_dict['sout']) pdf.cell(0, h=5, txt=text, ln=1) else: msg = """ Invalid Resource Name provided. The following options are available: - Summary - CPU - Memory - Network - Storage - Process - Miscellaneous """ raise ArgumentError(msg) return pdf
def create_qc_pdf(**kwargs): try: kwargs['company'] = kwargs.get('company', u'台茂化工儀器原料行') kwargs['product'] = kwargs.get('product', u'product name?') kwargs['ASE_pn'] = kwargs.get('ASE_pn', u'ASE PN?') if not kwargs.get('lot_no'): kwargs['make_date'] = date.today() kwargs['test_date'] = date.today() kwargs['lot_no'] = u'lot number?' else: year = 2000 + int(kwargs['lot_no'][1:3]) month = int(kwargs['lot_no'][3:5]) day = int(kwargs['lot_no'][5:7]) kwargs['make_date'] = date(year, month, day) kwargs['test_date'] = date(year, month, day) kwargs['exp_period'] = kwargs.get('exp_period', u'一年') kwargs['amount'] = kwargs.get('amount', u'amount?') kwargs['tester'] = kwargs.get('tester', u'tester?') kwargs['test_params'] = kwargs.get('test_params', []) except Exception as e: print e return # Set placement and style of values tm_branch = dict(x=30, y=25, w=178-30, h=10, align='C') product_name = dict(x=31, y=50, w=104-31, h=15, align='L') product_ASE_pn = dict(x=105, y=50, w=104-31, h=15, align='L') make_date = dict(x=31, y=65, w=104-31, h=8, align='L') test_date = dict(x=31, y=73, w=104-31, h=8, align='L') exp_period = dict(x=31, y=81, w=104-31, h=9, align='L') lot_no = dict(x=105, y=65, w=104-31, h=8, align='L') amount = dict(x=105, y=73, w=104-31, h=8, align='L') tester = dict(x=105, y=81, w=104-31, h=9, align='L') # Create PDF FPDF = myPDF('P','mm','A4') FPDF.set_compression(False) FPDF.set_creator('TM_2014') FPDF.set_title(u'Quality inspection report for lot# {}'.format(kwargs['lot_no'])) FPDF.set_author(u'Taimau Chemicals') FPDF.set_subject(kwargs['lot_no']) # FPDF.set_subject(u'{} {}'.format(kwargs['product'], kwargs['lot_no']), isUTF8=True) FPDF.alias_nb_pages() FPDF.add_page() # Adding a page also creates a page break from last page FPDF.add_font(family=u'SimHei', style='', fname=font, uni=True) # Only .ttf and not .ttc FPDF.set_font(family=u'SimHei', style='', size=16) FPDF.xycell(txt=kwargs['company'], **tm_branch) FPDF.set_font(family=u'SimHei', style='B', size=13) FPDF.xycell(txt=u'產品: {}'.format(kwargs['product']), **product_name) FPDF.xycell(txt=u'料號: {}'.format(kwargs['ASE_pn']), **product_ASE_pn) FPDF.xycell(txt=u'製造日期: {}'.format(kwargs['make_date']), **make_date) FPDF.xycell(txt=u'檢驗日期: {}'.format(kwargs['test_date']), **test_date) FPDF.xycell(txt=u'保存期間: {}'.format(kwargs['exp_period']), **exp_period) FPDF.xycell(txt=u'批號: {}'.format(kwargs['lot_no']), **lot_no) FPDF.xycell(txt=u'生產數量: {}'.format(kwargs['amount']), **amount) FPDF.xycell(txt=u'取樣人員: {}'.format(kwargs['tester']), **tester) FPDF.set_left_margin(30) FPDF.set_xy(x=30, y=105) for (a, b, c) in kwargs['test_params']: if a+b+c == u'': break FPDF.cell(49, 10, txt=a, align='C') FPDF.cell(49, 10, txt=b, align='C') FPDF.cell(49, 10, txt=c, align='C') FPDF.ln() FPDF.cell(49) FPDF.cell(49, 10, txt=u'以下空白', align='C') initialfilename = u'QC_{}_{}'.format(kwargs['product'], kwargs['lot_no']) FILE_OPTS = dict( title = u'PDF name and location.', defaultextension = '.pdf', initialdir = os.path.expanduser('~') + '/Desktop/', initialfile = initialfilename, ) if settings.load().get(u'pdfpath'): FILE_OPTS['initialdir'] = settings.load()[u'pdfpath'] outfile = os.path.normpath(tkFileDialog.asksaveasfilename(**FILE_OPTS)) if os.path.exists(outfile): os.remove(outfile) if outfile and not os.path.exists(outfile): FPDF.output(name=outfile) try: subprocess.call(['start', outfile], shell=True) return except: pass try: print u'Trying alternate subprocess command.' subprocess.call(['start', '/D'] + list(os.path.split(outfile)), shell=True) return except UnicodeEncodeError: pass try: os.startfile(outfile) return except: pass print u'Failed to autoload PDF after creation.' return else: head = u'Cancelled' body = u'Canceled PDF creation.' tkMessageBox.showinfo(head, body)
class PdfHandler: def __init__(self, orientation='P', unit='pt', format='A4'): self.pdf_handler = FPDF(orientation=orientation, unit=unit, format=format) def _set_margins(self, left, top, right=-1): return self.pdf_handler.set_margins(left, top, right=right) def _set_title(self, title): return self.pdf_handler.set_title(title) def _set_subject(self, subject): return self.pdf_handler.set_subject(subject) def _set_author(self, author): return self.pdf_handler.set_author(author) def _set_keywords(self, keywords): return self.pdf_handler.set_keywords(keywords) def _set_creator(self, creator): return self.pdf_handler.set_creator(creator) def _add_page(self, orientation=''): return self.pdf_handler.add_page(orientation=orientation) def _set_draw_color(self, r, g=-1, b=-1): return self.pdf_handler.set_draw_color(r, g=g, b=b) def _set_fill_color(self, r, g=-1, b=-1): return self.pdf_handler.set_fill_color(g=g, b=b) def _set_text_color(self, r, g=-1, b=-1): return self.pdf_handler.set_text_color(r, g=-g, b=b) def _get_string_width(self, s): return self.pdf_handler.get_string_width(s) def _set_line_width(self, width): return self.pdf_handler.set_line_width(width) def _line(self, x1, y1, x2, y2): return self.pdf_handler.line(x1, y1, x2, y2) def _dashed_line(self, x1, y1, x2, y2, dash_length=1, space_length=1): return self.pdf_handler.dashed_line(x1, y1, x2, y2, dash_length=dash_length, space_length=space_length) def _rect(self, x, y, w, h, style=''): return self.pdf_handler.rect(x, y, w, h, style=style) def _ellipse(self, x, y, w, h, style=''): return self.pdf_handler.ellipse(x, y, w, h, style=style) def _set_font(self, family, style='', size=0): return self.pdf_handler.set_font(family, style=style, size=size) def _set_font_size(self, size): return self.pdf_handler.set_font_size(size) def _text(self, x, y, txt=''): return self.pdf_handler.text(x, y, txt=txt) def _multi_cell(self, w, h, txt='', border=0, align='J', fill=0, split_only=False): return self.pdf_handler.multi_cell(w, h, txt=txt, border=border, align=align, fill=fill, split_only=split_only) def _write(self, h, txt='', link=''): return self.pdf_handler.write(h, txt=txt, link=link) def _image(self, name, x=None, y=None, w=0, h=0, image_type='', link=''): return self.pdf_handler.image(name, x=x, y=y, w=w,h=h,type=image_type,link=link) def _normalize_text(self, txt): return self.pdf_handler.normalize_text(txt) def _output(self, name='', dest=''): return self.pdf_handler.output(name, dest)
class Kut2FPDF(object): """ Convert kuts to pyFPDF. """ _document: "FPDF" _xml: Element _xml_data: Element _page_orientation: str _page_size: List[int] _bottom_margin: int _left_margin: int _right_margin: int _top_margin: int _page_top: Dict[int, int] _data_row: Element _parser_tools: "kparsertools.KParserTools" _avalible_fonts: List[str] _unavalible_fonts: List[str] design_mode: bool _actual_data_line: Optional[Element] _no_print_footer: bool _actual_section_size: int increase_section_size: int last_detail: bool actual_data_level: int last_data_processed: Element prev_level: int draws_at_header: Dict[str, str] detailn: Dict[str, int] name_: str _actual_append_page_no: int reset_page_count: bool def __init__(self) -> None: """Constructor.""" check_dependencies({"fpdf": "fpdf2"}) self._parser_tools = kparsertools.KParserTools() self._avalible_fonts = [] self._page_top: Dict[int, int] = {} self._unavalible_fonts = [] self.design_mode = config.value("ebcomportamiento/kugar_debug_mode", False) self._actual_data_line = None self._no_print_footer = False self.increase_section_size = 0 self.actual_data_level = 0 self.prev_level = -1 self.draws_at_header = {} self.detailn = {} self.name_ = "" self._actual_append_page_no = -1 self.reset_page_count = False self.new_page = False def parse(self, name: str, kut: str, data: str, report: "FPDF" = None, flags: List[int] = []) -> Optional[str]: """ Parse string containing ".kut" file into a pdf and return its file path. @param name. Filename path for ".kut". @param kut. String with ".kut" file contents. @param data. String with data to be used in the report. @return Path to PDF file. """ try: self._xml = self._parser_tools.loadKut(kut).getroot() except Exception: LOGGER.exception("KUT2FPDF: Problema al procesar %s.kut", name) return None try: self._xml_data = load2xml(data).getroot() except Exception: LOGGER.exception("KUT2FPDF: Problema al procesar xml_data") return None application.PROJECT.message_manager().send( "progress_dialog_manager", "create", ["Pineboo", len(self._xml_data), "kugar"]) application.PROJECT.message_manager().send( "progress_dialog_manager", "setLabelText", ["Creando informe ...", "kugar"]) self.name_ = name self.setPageFormat(self._xml) # self._page_orientation = # self._page_size = if report is None: from fpdf import FPDF # type: ignore self._actual_append_page_no = 0 self._document = FPDF(self._page_orientation, "pt", self._page_size) for font in self._document.core_fonts: LOGGER.debug("KUT2FPDF :: Adding font %s", font) self._avalible_fonts.append(font) else: self._document = report # Seteamos rutas a carpetas con tipos de letra ... if not hasattr(self._document, "set_stretching"): raise Exception("incorrect pyfpdf versión , you need <= 1.7.3") # Cargamos las fuentes disponibles next_page_break = (flags[2] == 1) if len(flags) == 3 else True page_append = (flags[1] == 1) if len(flags) > 1 else False page_display = (flags[0] == 1) if len(flags) > 0 else False if page_append: self.prev_level = -1 self.last_detail = False page_break = False if self.new_page: page_break = True self.new_page = False if self.reset_page_count: self.reset_page_no() self.reset_page_count = False if self.design_mode: print("Append", page_append) print("Display", page_display) print("Page break", next_page_break) if next_page_break: self.reset_page_count = True if page_display: self.new_page = True self.processDetails(not page_break) # FIXME:Alguno valores no se encuentran for pages in self._document.pages.keys(): page_content = self._document.pages[pages]["content"] for header in self.draws_at_header.keys(): page_content = page_content.replace( header, str(self.draws_at_header[header])) self._document.pages[pages]["content"] = page_content # print(self.draws_at_header.keys()) self._document.set_title(self.name_) self._document.set_author("Pineboo - kut2fpdf plugin") return self._document def get_file_name(self) -> Optional[str]: """Retrieve file name where PDF should be saved.""" import os pdf_name = application.PROJECT.tmpdir pdf_name += "/%s_%s.pdf" % ( self.name_, datetime.datetime.now().strftime("%Y%m%d%H%M%S")) if os.path.exists(pdf_name): os.remove(pdf_name) if self._document is not None: self._document.output(pdf_name, "F") return pdf_name else: return None def topSection(self) -> int: """ Retrieve top section margin for current page to calculate object positions. @return Number with ceiling for current page. """ return self._page_top[int(self._document.page_no())] def setTopSection(self, value: int) -> None: """ Update top section for current page. Usually updated when processing a section. @param value. Number specifying new ceiling. """ self._actual_section_size = value - self.topSection() self._page_top[int(self._document.page_no())] = value def newPage(self, data_level: int, add_on_header: bool = True) -> None: """ Add a new page to the document. """ self._document.add_page(self._page_orientation) self._page_top[int(self._document.page_no())] = self._top_margin self._document.set_margins( self._left_margin, self._top_margin, self._right_margin) # Lo dejo pero no se nota nada self._no_print_footer = False if self.design_mode: self.draw_margins() self._actual_section_size = 0 self._actual_append_page_no += 1 if self.design_mode: print("Nueva página", self.number_pages()) # l_ini = data_level # l_end = self.prev_level # if l_ini == l_end: # l_end = l_end + 1 # if l_ini <= l_end: # for l in range(l_ini , l_end): # print(l) # self.processSection("AddOnHeader", str(l)) pg_headers = self._xml.findall("PageHeader") for page_header in pg_headers: if self.number_pages() == 1 or page_header.get( "PrintFrequency") == "1": ph_level = (page_header.get("Level") if page_header.get("Level") is not None else None) self.processSection("PageHeader", int(ph_level or "0")) break if add_on_header and not self.number_pages() == 1: for level in range(data_level + 1): self.processSection("AddOnHeader", int(level)) # Por ahora se omite detail header def processDetails(self, keep_page: Optional[bool] = None) -> None: """ Process detail secions with their matching detailHeader and detailFooter. """ # Procesamos la cabecera si procede .. top_level = 0 level = 0 first_page_created = (keep_page if keep_page is not None and self._document.page_no() > 0 else False) rows_array = self._xml_data.findall("Row") i = 0 for data in rows_array: self._actual_data_line = data level_str: Optional[str] = data.get("level") if level_str is None: level_str = "0" level = int(level_str) if level > top_level: top_level = level if not first_page_created: self.newPage(level) first_page_created = True if rows_array[len(rows_array) - 1] is data: self.last_detail = True if level < self.prev_level: for lev in range(level + 1, self.prev_level + 1): self.processData("DetailFooter", self.last_data_processed, lev) if not str(level) in self.detailn.keys(): self.detailn[str(level)] = 0 else: self.detailn[str(level)] += 1 if level > self.prev_level: self.processData("DetailHeader", data, level) self.processData("Detail", data, level) self.last_data_processed = data self.prev_level = level application.PROJECT.message_manager().send( "progress_dialog_manager", "setProgress", [i, "kugar"]) i += 1 if not self._no_print_footer and hasattr(self, "last_data_processed"): for lev in reversed(range(top_level + 1)): self.processData("DetailFooter", self.last_data_processed, lev) application.PROJECT.message_manager().send("progress_dialog_manager", "destroy", ["kugar"]) def processData(self, section_name: str, data: Element, data_level: int) -> None: """ Check if detailHeader + detail + detailFooter do fit in the remaining page and create a new page if not. @param section_name. Section name to check @param data. Data to check @param data_level. Section level """ self.actual_data_level = data_level list_sections = self._xml.findall(section_name) # data_size = len(listDF) for section in list_sections: draw_if = section.get("DrawIf") show = True if draw_if: show = bool(data.get(draw_if)) if section.get("Level") == str(data_level) and show not in ( "", "False", "None"): if section_name in ("DetailHeader", "Detail"): height_calculated = ( self._parser_tools.getHeight(section) + self.topSection() + self.increase_section_size) if section_name == "DetailHeader": for detail in self._xml.findall("Detail"): if detail.get("Level") == str(data_level): height_calculated += self._parser_tools.getHeight( detail) for detail_footer in self._xml.findall("DetailFooter"): if detail_footer.get("Level") == str(data_level): height_calculated += self._parser_tools.getHeight( detail_footer) aof_size = 0 for add_footer in self._xml.findall("AddOnFooter"): # if add_footer.get("Level") == str(data_level): aof_size += self._parser_tools.getHeight(add_footer) height_calculated += self._parser_tools.getHeight( add_footer) page_footer: Any = self._xml.get("PageFooter") if isinstance(page_footer, Element): if (self._document.page_no() == 1 or page_footer.get("PrintFrecuency") == "1"): height_calculated += self._parser_tools.getHeight( page_footer) height_calculated += self._bottom_margin if (height_calculated + aof_size) > self._document.h: # Si nos pasamos self._no_print_footer = True # Vemos el tope por abajo limit_bottom = self._document.h - aof_size actual_size = self._parser_tools.getHeight( section) + self.topSection() if (actual_size >= limit_bottom - 2 ) or self.last_detail: # +2 se usa de margen extra self.processSection("AddOnFooter", int(data_level)) self.newPage(data_level) self.processXML(section, data) if section.get("NewPage") == "true" and not self.last_detail: self.newPage(data_level, False) break # Se ejecuta una sola instancia def processSection(self, name: str, level: int = 0) -> None: """ Process non-detail sections. @param name. Section name to process """ sec_list = self._xml.findall(name) sec_ = None for section in sec_list: if section.get("Level") == str( level) or section.get("Level") is None: sec_ = section break if sec_ is not None: if (sec_.get("PrintFrequency") == "1" or self._document.page_no() == 1 or name in ("AddOnHeader", "AddOnFooter")): self.processXML(sec_) def processXML(self, xml: Element, data: Optional[Element] = None) -> None: """ Process single XML element. @param xml: Element to process @param. data: Line affected """ fix_height = True if data is None: data = self._actual_data_line if self.design_mode and data is not None: print("Procesando", xml.tag, data.get("level")) size_updated = False if xml.tag == "DetailFooter": if xml.get("PlaceAtBottom") == "true": height = self._parser_tools.getHeight(xml) self.setTopSection(self._document.h - height - self.increase_section_size) size_updated = True if xml.tag == "PageFooter": fix_height = False if not size_updated: self.fix_extra_size( ) # Sirve para actualizar la altura con lineas que se han partido porque son muy largas for label in xml.iter("Label"): self.processText(label, data, fix_height) for field in xml.iter("Field"): self.processText(field, data, fix_height) for special in xml.iter("Special"): self.processText(special, data, fix_height, xml.tag) for calculated in xml.iter("CalculatedField"): self.processText(calculated, data, fix_height, xml.tag) # Busco draw_at_header en DetailFooter y los meto también if xml.tag == "DetailHeader": detail_level = xml.get("Level") if detail_level is None: raise Exception("Level tag not found") for detail_footer in self._xml.iter("DetailFooter"): if detail_footer.get("Level") == detail_level: for calculated_filed in detail_footer.iter( "CalculatedField"): if calculated_filed.get("DrawAtHeader") == "true": header_name = "%s_header_%s_%s" % ( self.detailn[detail_level], detail_level, calculated_filed.get("Field"), ) self.draws_at_header[header_name] = "" self.processText(calculated_filed, data, fix_height, xml.tag) for line in xml.iter("Line"): self.processLine(line, fix_height) if not size_updated: self.setTopSection(self.topSection() + self._parser_tools.getHeight(xml)) def fix_extra_size(self) -> None: """Increase size of the section if needed.""" if self.increase_section_size > 0: self.setTopSection(self.topSection() + self.increase_section_size) self.increase_section_size = 0 def processLine(self, xml: Element, fix_height: bool = True) -> None: """ Process single line. @param xml. Sección de xml a procesar. @param fix_height. Ajusta la altura a los .kut originales, excepto el pageFooter. """ color = xml.get("Color") red = 0 if not color else int(color.split(",")[0]) green = 0 if not color else int(color.split(",")[1]) blue = 0 if not color else int(color.split(",")[2]) style = int(xml.get("Style") or "0") width = int(xml.get("Width") or "0") pos_x1 = self.calculateLeftStart(xml.get("X1") or "0") pos_x1 = self.calculateWidth(pos_x1, 0, False) pos_x2 = self.calculateLeftStart(xml.get("X2") or "0") pos_x2 = self.calculateWidth(pos_x2, 0, False) # Ajustar altura a secciones ya creadas pos_y1 = int(xml.get("Y1") or "0") + self.topSection() pos_y2 = int(xml.get("Y2") or "0") + self.topSection() if fix_height: pos_y1 = self._parser_tools.ratio_correction_h(pos_y1) pos_y2 = self._parser_tools.ratio_correction_h(pos_y2) self._document.set_line_width( self._parser_tools.ratio_correction_h(width)) self._document.set_draw_color(red, green, blue) dash_length = 1 space_length = 1 if style == 2: dash_length = 20 space_length = 20 elif style == 3: dash_length = 10 space_length = 10 self._document.dashed_line(pos_x1, pos_y1, pos_x2, pos_y2, dash_length, space_length) # else: # self._document.line(X1, Y1, X2, Y2) def calculateLeftStart(self, position: Union[str, int, float]) -> int: """ Check if left margin is exceeded for current page. @param position. Position to check. @return Revised position. """ return self._parser_tools.ratio_correction_w( int(position)) + self._left_margin def calculateWidth(self, width: int, pos_x: int, fix_ratio: bool = True) -> int: """ Check if right margin is exceeded for current page. @param x. Position to check. @return Revised position. """ limit = self._document.w - self._right_margin ret_: int if fix_ratio: width = self._parser_tools.ratio_correction_w(width) pos_x = self._parser_tools.ratio_correction_w(pos_x) ret_ = width if pos_x + width > limit: ret_ = limit - pos_x else: ret_ = width return ret_ def processText( self, xml: Element, data_row: Optional[Element] = None, fix_height: bool = True, section_name: Optional[str] = None, ) -> None: """ Check tag (calculated, label, special or image). @param xml. XML section to process. @param fix_height. Revise height from original .kut file except pageFooter. """ is_image = False is_barcode = False text: str = xml.get("Text") or "" # borderColor = xml.get("BorderColor") field_name = xml.get("Field") or "" # x,y,W,H se calcula y corrigen aquí para luego estar correctos en los diferentes destinos posibles width = int(xml.get("Width") or "0") height = self._parser_tools.getHeight(xml) pos_x = int(xml.get("X") or "0") pos_y = (int(xml.get("Y") or "0") + self.topSection() ) # Añade la altura que hay ocupada por otras secciones if fix_height: pos_y = self._parser_tools.ratio_correction_h( pos_y) # Corrige la posición con respecto al kut original data_type = xml.get("DataType") if xml.tag == "Field" and data_row is not None: text = data_row.get(field_name) or "" elif xml.tag == "Special": if text == "": if xml.get("Type") == "1": text = "PageNo" text = self._parser_tools.getSpecial(text, self._actual_append_page_no) calculation_type = xml.get("CalculationType") if calculation_type is not None and xml.tag != "Field": if calculation_type == "6": function_name = xml.get("FunctionName") if function_name and data_row is not None: try: nodo = self._parser_tools.convertToNode(data_row) ret_ = application.PROJECT.call( function_name, [nodo, field_name], None, False) if ret_ is False: return else: text = str(ret_) except Exception: LOGGER.exception( "KUT2FPDF:: Error llamando a function %s", function_name) return else: return elif calculation_type == "1": text = self._parser_tools.calculate_sum( field_name, self.last_data_processed, self._xml_data, self.actual_data_level) elif calculation_type in ("5"): if data_row is None: data_row = self._xml_data[0] text = data_row.get(field_name) or "" if data_type is not None: text = self._parser_tools.calculated(text, int(data_type), xml.get("Precision"), data_row) if data_type == "5": is_image = True elif data_type == "6": is_barcode = True if xml.get("BlankZero") == "1" and text is not None: res_ = re.findall(r"\d+", text) if res_ == ["0"]: return if text is not None: from pineboolib.core.settings import config temporal = config.value("ebcomportamiento/temp_dir") if text.startswith(temporal): is_image = True # negValueColor = xml.get("NegValueColor") # Currency = xml.get("Currency") # # commaSeparator = xml.get("CommaSeparator") # dateFormat = xml.get("DateFormat") if is_image: self.draw_image(pos_x, pos_y, width, height, xml, text) elif is_barcode: self.draw_barcode(pos_x, pos_y, width, height, xml, text) elif data_row is not None: level = data_row.get("level") or "0" if level and str(level) in self.detailn.keys(): val = "%s_header_%s_%s" % (self.detailn[str(level)], level, field_name) if xml.get("DrawAtHeader") == "true" and level: if section_name == "DetailHeader": val = "" self.drawText(pos_x, pos_y, width, height, xml, val) # print(level, section_name, val, text) if section_name == "DetailFooter" and xml.get( "DrawAtHeader") == "true": self.draws_at_header[val] = text # print("Añadiendo a", val, text, level) else: self.drawText(pos_x, pos_y, width, height, xml, text) def drawText(self, pos_x: int, pos_y: int, width: int, height: int, xml: Element, txt: str) -> None: """ Draw a text field onto the page. @param pos_x. Label X Pos. @param pos_y. Label Y Pos. @param width. Label Width. @param height. Label Height. @param xml. Related XML Section @param txt. Computed text of the label to be created. """ if txt in ("None", None): # return txt = "" if width == 0 and height == 0: return txt = self._parser_tools.restore_text(txt) resizeable = False if xml.get("ChangeHeight") == "1": resizeable = True # height_resized = False orig_x = pos_x orig_y = pos_y orig_w = width orig_h = height # Corregimos margenes: pos_x = self.calculateLeftStart(pos_x) width = self.calculateWidth(width, pos_x) # bg_color = xml.get("BackgroundColor").split(",") fg_color = self.get_color(xml.get("ForegroundColor") or "") self._document.set_text_color(fg_color[0], fg_color[1], fg_color[2]) # self._document.set_draw_color(255, 255, 255) # if xml.get("BorderStyle") == "1": # FIXME: Hay que ajustar los margenes # font_name, font_size, font_style font_style = "" font_size = int(xml.get("FontSize") or "0") font_name_orig = ((xml.get("FontFamily") or "").lower() if xml.get("FontFamily") is not None else "helvetica") font_name = font_name_orig font_w = int(xml.get("FontWeight") or "50") if font_w == 50: # Normal font_w = 100 elif font_w >= 65: font_style += "B" font_w = 100 font_italic = xml.get("FontItalic") font_underlined = xml.get( "FontUnderlined") # FIXME: hay que ver si es así # background_color = self.get_color(xml.get("BackgroundColor")) # if background_color != [255,255,255]: #Los textos que llevan fondo no blanco van en negrita # font_style += "B" if font_italic == "1": font_style += "I" if font_underlined == "1": font_style += "U" font_name = font_name.replace(" narrow", "") font_full_name = "%s%s" % (font_name, font_style) if font_full_name not in self._avalible_fonts: font_found: Optional[str] = None if font_full_name not in self._unavalible_fonts: font_found = self._parser_tools.find_font( font_full_name, font_style) if font_found: if self.design_mode: LOGGER.warning( "KUT2FPDF::Añadiendo el tipo de letra %s %s (%s)", font_name, font_style, font_found, ) self._document.add_font(font_name, font_style, font_found, True) self._avalible_fonts.append(font_full_name) else: if font_full_name not in self._unavalible_fonts: if self.design_mode: LOGGER.warning( "KUT2FPDF:: No se encuentra el tipo de letra %s. Sustituido por helvetica%s." % (font_full_name, font_style)) self._unavalible_fonts.append(font_full_name) font_name = "helvetica" if font_name is not font_name_orig and font_name_orig.lower().find( "narrow") > -1: font_w = 85 self._document.set_font(font_name, font_style, font_size) self._document.set_stretching(font_w) # Corregir alineación vertical_alignment = xml.get( "VAlignment") # 0 izquierda, 1 centrado,2 derecha horizontal_alignment = xml.get("HAlignment") # layout_direction = xml.get("layoutDirection") start_section_size = self._actual_section_size result_section_size = 0 # Miramos si el texto sobrepasa el ancho array_text: List[str] = [] array_n = [] text_lines = [] if txt.find("\n") > -1: for line_text in txt.split("\n"): array_n.append(line_text) if array_n: # Hay saltos de lineas ... for n in array_n: text_lines.append(n) else: # No hay saltos de lineas text_lines.append(txt) for text_line in text_lines: if len(text_line) > 1: if text_line[0] == " " and text_line[1] != " ": text_line = text_line[1:] str_width = self._document.get_string_width(text_line) if ( str_width > width - 10 and xml.tag != "Label" and resizeable ): # Una linea es mas larga que el ancho del campo(Le quito 10 al ancho maximo para que corte parecido a kugar original) # height_resized = True array_text = self.split_text(text_line, width - 10) else: array_text.append(text_line) # calculated_h = orig_h * len(array_text) self.drawRect(orig_x, orig_y, orig_w, orig_h, xml) processed_lines = 0 extra_size = 0 for actual_text in array_text: processed_lines += 1 if processed_lines > 1: extra_size += font_size + 2 if horizontal_alignment == "1": # sobre X # Centrado pos_x = pos_x + (width / 2) - ( self._document.get_string_width(actual_text) / 2) # x = x + (width / 2) - (str_width if not height_resized else width / 2) elif horizontal_alignment == "2": # Derecha pos_x = (pos_x + width - self._document.get_string_width(actual_text) - 2 ) # -2 de margen # x = x + width - str_width if not height_resized else width else: # Izquierda if processed_lines == 1: pos_x = pos_x + 2 if vertical_alignment == "1": # sobre Y # Centrado # y = (y + ((H / 2) / processed_lines)) + (((self._document.font_size_pt / 2) / 2) * processed_lines) pos_y = int((orig_y + (orig_h / 2)) + ((self._document.font_size_pt / 2) / 2)) if len(array_text) > 1: pos_y = pos_y - (font_size // 2) elif vertical_alignment == "2": # Abajo pos_y = orig_y + orig_h - font_size else: # Arriba pos_y = orig_y + font_size pos_y = pos_y + extra_size if self.design_mode: self.write_debug( self.calculateLeftStart(orig_x), pos_y, "Hal:%s, Val:%s, T:%s st:%s" % (horizontal_alignment, vertical_alignment, txt, font_w), 6, "green", ) if xml.tag == "CalculatedField": self.write_debug( self.calculateLeftStart(orig_x), pos_y, "CalculatedField:%s, Field:%s" % (xml.get("FunctionName"), xml.get("Field")), 3, "blue", ) self._document.text(pos_x, pos_y, actual_text) result_section_size += start_section_size result_section_size = result_section_size - start_section_size if (self.increase_section_size < extra_size ): # Si algun incremento extra hay superior se respeta self.increase_section_size = extra_size def split_text(self, texto: str, limit_w: int) -> List[str]: """Split text into lines based on visual width.""" list_ = [] linea_: Optional[str] = None for parte in texto.split(" "): if linea_ is None and parte == "": continue if linea_ is not None: if self._document.get_string_width(linea_ + parte) > limit_w: list_.append(linea_) linea_ = "" else: linea_ = "" linea_ += "%s " % parte if linea_ is not None: list_.append(linea_) return list_ def get_color(self, value: str) -> List[int]: """Convert color text into [r,g,b] array.""" lvalue = value.split(",") red: int green: int blue: int if len(lvalue) == 3: red = int(lvalue[0]) green = int(lvalue[1]) blue = int(lvalue[2]) else: red = int(value[0:2]) green = int(value[3:5]) blue = int(value[6:8]) return [red, green, blue] def drawRect(self, pos_x: int, pos_y: int, width: int, height: int, xml: Element = None) -> None: """ Draw a rectangle in current page. @param pos_x. left side @param pos_y. top side @param width. width @param height. heigth """ style_ = "" border_color = None bg_color = None line_width = self._document.line_width border_width = 0.2 # Calculamos borde y restamos del ancho orig_x = pos_x orig_y = pos_y orig_w = width pos_x = self.calculateLeftStart(orig_x) width = self.calculateWidth(width, pos_x) if xml is not None and not self.design_mode: if xml.get("BorderStyle") == "1": border_color = self.get_color(xml.get("BorderColor") or "") self._document.set_draw_color(border_color[0], border_color[1], border_color[2]) style_ += "D" bg_color = self.get_color(xml.get("BackgroundColor") or "") self._document.set_fill_color(bg_color[0], bg_color[1], bg_color[2]) style_ = "F" + style_ border_width = int( xml.get("BorderWidth") or "0" if xml.get("BorderWidth" ) else 0.2) else: self.write_cords_debug(pos_x, pos_y, width, height, orig_x, orig_w) style_ = "D" self._document.set_draw_color(0, 0, 0) if style_ != "": self._document.set_line_width(border_width) self._document.rect(pos_x, pos_y, width, height, style_) self._document.set_line_width(line_width) self._document.set_xy(orig_x, orig_y) # self._document.set_draw_color(255, 255, 255) # self._document.set_fill_color(0, 0, 0) def write_cords_debug( self, pos_x: Union[float, int], pos_y: Union[float, int], width: Union[float, int], height: Union[float, int], orig_x: Union[float, int], orig_w: Union[float, int], ) -> None: """Debug for Kut coordinated.""" self.write_debug( int(pos_x), int(pos_y), "X:%s Y:%s W:%s H:%s orig_x:%s, orig_W:%s" % ( round(pos_x, 2), round(pos_y, 2), round(width, 2), round(height, 2), round(orig_x, 2), round(orig_w, 2), ), 2, "red", ) def write_debug(self, pos_x: int, pos_y: int, text: str, height: int, color: Optional[str] = None) -> None: """Write debug data into the report.""" orig_color = self._document.text_color red = 0 green = 0 blue = 0 current_font_family = self._document.font_family current_font_size = self._document.font_size_pt current_font_style = self._document.font_style if color == "red": red = 255 elif color == "green": green = 255 elif color == "blue": blue = 255 self._document.set_text_color(red, green, blue) self._document.set_font_size(4) self._document.text(pos_x, pos_y + height, text) self._document.text_color = orig_color # self._document.set_xy(orig_x, orig_y) self._document.set_font(current_font_family, current_font_style, current_font_size) def draw_image(self, pos_x: int, pos_y: int, width: int, height: int, xml: Element, file_name: str) -> None: """ Draw image onto current page. @param pos_x. left position @param pos_y. top position @param width. width @param height. heigth @param xml. Related XML section @param file_name. filename of temp data to use """ import os if not file_name.lower().endswith(".png"): file_name_ = self._parser_tools.parseKey(file_name) if file_name_ is None: return file_name = file_name_ if os.path.exists(file_name): pos_x = self.calculateLeftStart(pos_x) width = self.calculateWidth(width, pos_x) self._document.image(file_name, pos_x, pos_y, width, height, "PNG") def draw_barcode(self, pos_x: int, pos_y: int, width: int, height: int, xml: Element, text: str) -> None: """ Draw barcode onto currrent page. """ if text == "None": return from pineboolib.fllegacy import flcodbar file_name = application.PROJECT.tmpdir file_name += "/%s.png" % (text) codbartype = xml.get("CodBarType") if not os.path.exists(file_name): bar_code = flcodbar.FLCodBar(text) # Code128 if codbartype is not None: type: int = bar_code.nameToType(codbartype.lower()) bar_code.setType(type) bar_code.setText(text) pix = bar_code.pixmap() if not pix.isNull(): pix.save(file_name, "PNG") self.draw_image(pos_x + 10, pos_y, width - 20, height, xml, file_name) def setPageFormat(self, xml: Element) -> None: """ Define page parameters. @param xml: XML with KUT data """ custom_size = None self._bottom_margin = int(xml.get("BottomMargin") or "0") self._left_margin = int(xml.get("LeftMargin") or "0") self._right_margin = int(xml.get("RightMargin") or "0") self._top_margin = int(xml.get("TopMargin") or "0") page_size = int(xml.get("PageSize") or "0") page_orientation = xml.get("PageOrientation") or "0" if page_size in [30, 31]: custom_size = [ int(xml.get("CustomHeightMM") or "0"), int(xml.get("CustomWidthMM") or "0"), ] self._page_orientation = "P" if page_orientation == "0" else "L" self._page_size = self._parser_tools.convertPageSize( page_size, int(page_orientation), custom_size) # devuelve un array def draw_margins(self) -> None: """Draw margins on the report.""" self.draw_debug_line(0 + self._left_margin, 0, 0 + self._left_margin, self._page_size[1]) # Vertical derecha self.draw_debug_line( self._page_size[0] - self._right_margin, 0, self._page_size[0] - self._right_margin, self._page_size[1], ) # Vertical izquierda self.draw_debug_line(0, 0 + self._top_margin, self._page_size[0], 0 + self._top_margin) # Horizontal superior self.draw_debug_line( 0, self._page_size[1] - self._bottom_margin, self._page_size[0], self._page_size[1] - self._bottom_margin, ) # Horizontal inferior def draw_debug_line( self, pos_x1: int, pos_y1: int, pos_x2: int, pos_y2: int, title: Optional[str] = None, color: str = "GREY", ) -> None: """Draw a debug line on the report.""" dash_length = 2 space_length = 2 red = 0 green = 0 blue = 0 if color == "GREY": red = 220 green = 220 blue = 220 self._document.set_line_width(1) self._document.set_draw_color(red, green, blue) self._document.dashed_line(pos_x1, pos_y1, pos_x2, pos_y1, dash_length, space_length) def number_pages(self) -> int: """Get number of pages on the report.""" return self._actual_append_page_no if self._actual_append_page_no > 0 else 0 def reset_page_no(self) -> None: """Reset page number.""" self._actual_append_page_no = -1
def gen_pdf(font_path: str, pdf_path: str, pe_ost_list: list[pe_T], pt_ost_list: list[pt_T]) -> None: """Generate PDF file with per-episode and per-track listings from per-episode OST list.""" font_family = "ext_font" page_margin = 10 font_size = 10 cell_h = 5 cell_padding = 10 # compute cells and page size pdf = FPDF() pdf.add_font(font_family, fname=font_path, uni=True) pdf.set_font(font_family, size=font_size) page_h = 0 max_col_w = { key: pdf.get_string_width(col_name_dict[key]) for key in col_name_dict } # init with column name width for ep_dict in pe_ost_list: page_h += cell_h * len(ep_dict[pe_list_key]) first_col_key = pe_col_list[0] max_col_w[first_col_key] = max( max_col_w[first_col_key], pdf.get_string_width(ep_dict[first_col_key])) for track_dict in ep_dict[pe_list_key]: for key in track_dict: max_col_w[key] = max(max_col_w[key], pdf.get_string_width(track_dict[key])) col_w = {key: max_col_w[key] + cell_padding for key in max_col_w} page_w = sum(col_w.values()) + 2 * page_margin page_h += 3 * page_margin + font_size # init PDF pdf = FPDF(format=(page_w, page_h)) pdf.set_author("DSAureli") pdf.set_creation_date(datetime.date.today()) pdf.set_title(proj_title) pdf.set_margins(page_margin, page_margin) pdf.add_font(font_family, fname=font_path, uni=True) pdf.set_font(font_family, size=font_size) pdf.set_auto_page_break(False) # define table generating function def gen_table(col_list: list[str], ost_list: list[TypeVar("T", pe_T, pt_T)], list_key: str) -> None: """ Generate table with columns as in 'col_list' and data as in 'ost_list'. 'list_key' is the key for the list inside each dictionary in 'ost_list'. """ # column titles for key in col_list: pdf.cell(w=col_w[key], h=2 * cell_h, border=1, align="C", txt=col_name_dict[key]) pdf.ln() for head_dict in ost_list: # header cell, spanning multiple rows pdf.cell(w=col_w[col_list[0]], h=len(head_dict[list_key]) * cell_h, border=1, align="C", txt=head_dict[col_list[0]]) pdf.ln(h=0) # line feed, but don't increase y coord for row_dict in head_dict[list_key]: pdf.set_x(pdf.get_x() + col_w[col_list[0]]) # place cursor after header cell for key in row_dict: pdf.cell(w=col_w[key], h=cell_h, border=1, align="C", txt=row_dict[key]) pdf.ln() # generate per-episode page pdf.add_page() pdf.cell(w=0, align="C", txt=f"{proj_title} ~ per-episode") pdf.ln(h=page_margin) gen_table(pe_col_list, pe_ost_list, pe_list_key) # generate per-track page pdf.add_page() pdf.cell(w=0, align="C", txt=f"{proj_title} ~ per-track") pdf.ln(h=page_margin) gen_table(pt_col_list, pt_ost_list, pt_list_key) # write PDF to file pdf.output(pdf_path)
def save_history(request): stdate, spdate = None, None if 'stdate' in request.GET: stdate = datetime.datetime.strptime(request.GET.get('stdate'), '%d.%m.%Y') if 'spdate' in request.GET: spdate = datetime.datetime.strptime(request.GET.get('spdate'), '%d.%m.%Y') if stdate and spdate: o = Order.objects.filter(Q(date__gte=stdate) & Q(date__lte=spdate)).order_by('date') domain = Site.objects.get_current().domain def ImprovedTable(pdf, oo, data): header = [_(u"#id"), _(u"Title"), _(u"Price"), _(u"Count"), _(u"Cost")] w = [20, 70, 20, 20, 20] for i in range(len(header)): pdf.cell(w[i], 5, u'%s' % header[i], 1, 0, 'C', 1) pdf.ln() for row in data: pdf.cell(w[0], 5, u'%d' % row.product.id, 'LR') pdf.cell(w[1], 5, u'%s' % row.product.title, 'LR') pdf.cell(w[2], 5, u'%d' % row.get_cost(), 'LR', 0, 'R') pdf.cell(w[3], 5, u'%d' % row.count, 'LR', 0, 'R') pdf.cell(w[4], 5, u'%d' % row.get_total_cost(), 'LR', 0, 'R') pdf.ln() if oo.is_delivery: pdf.cell(w[0], 5, u'-', 'LR') pdf.cell(w[1], 5, _(u"Delivery"), 'LR') pdf.cell(w[2], 5, u'%d' % oo.cost_delivery, 'LR', 0, 'R') pdf.cell(w[3], 5, u'-', 'LR', 0, 'R') pdf.cell(w[4], 5, u'%d' % oo.cost_delivery, 'LR', 0, 'R') pdf.ln() pdf.cell(sum(w), 0, '', 'T') return pdf pdf = FPDF('P','mm','A4') pdf.set_author(domain) pdf.add_page() pdf.add_font('DejaVu', '', 'DejaVuSansCondensed.ttf', uni=True) pdf.add_font('DejaVuBold', '', 'DejaVuSansCondensed-Bold.ttf', uni=True) pdf.set_fill_color(229, 229, 229); pdf.set_font('DejaVu', '', 5); pdf.write(5, _(u"History created at %s") % datetime.datetime.now().strftime('%d.%m.%Y %H:%M')) pdf.ln(5) pdf.set_font('DejaVuBold', '', 8); pdf.write(5, _(u"History")) pdf.ln(5) for x in o: op = x.get_op() if op.count(): pdf.set_font('DejaVuBold', '', 8); pdf.write(5, u'Order #%d at %s on sum %d. Status: %s. Products:' % ( x.id, x.date.strftime('%d.%m.%Y %H:%M'), x.get_total_cost(), x.status.title )) pdf.ln(5) pdf.set_font('DejaVu', '', 5); pdf = ImprovedTable(pdf, x, x.get_op()) pdf.ln(5) s = pdf.output('History.pdf', 'S') response = HttpResponse(s, mimetype='application/pdf; charset=cp1251') response['Content-Disposition'] = 'attachment; filename=History.pdf' return response return HttpResponse('')
def insert_img(x): global downloads image_location = downloads + x img = cv2.imread(image_location) i, j, k = img.shape if i < j: rotated = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE) cv2.imwrite(image_location, rotated) pdf.image(image_location, x=0, y=0, w=8.27, h=11.69) ls = os.listdir(downloads) pdf = FPDF("P", "in", "A4") pdf.add_page() pdf.set_font("Arial", "B", 32) pdf.set_author("Suphal Bhattarai") pdf.set_creator("Suphal Bhattarai") pdf.set_title("Homework") pdf.set_fill_color(0, 0, 0) pdf.set_text_color(255, 255, 255) pdf.rect(0, 0, 8.27, 11.69, "FD") pdf.set_xy(1.5, 4) pdf.multi_cell(0, 0.5, "Name : Suphal Bhattarai \n Section : D6 \n Group : Biology", 0, 2, "C") for x in ls: if match(".*.jpg", x): pdf.add_page() insert_img(x)
def fetch_images_and_return_response(deck_code: str): code = deck_code file_name = deck_code # html = requests.get("https://www.pokemon-card.com/deck/deck.html?deckID=11F1Fw-VNG8m4-fk1bVF").content html = requests.get("https://www.pokemon-card.com/deck/deck.html?deckID=" + code).content soup = BeautifulSoup(html, "html.parser") card_data_script_text = soup.find_all("script")[-1].contents[0] # deck_pke_list の例: [["33525", "3"], ["33525", "3"]] deck_pke_list = [elem.split("_")[:2] for elem in soup.find(id="deck_pke")["value"].split("-")] deck_gds_list = [elem.split("_")[:2] for elem in soup.find(id="deck_gds")["value"].split("-")] \ if soup.find(id="deck_gds")["value"] != "" else [] deck_sup_list = [elem.split("_")[:2] for elem in soup.find(id="deck_sup")["value"].split("-")] \ if soup.find(id="deck_sup")["value"] != "" else [] deck_sta_list = [elem.split("_")[:2] for elem in soup.find(id="deck_sta")["value"].split("-")] \ if soup.find(id="deck_sta")["value"] != "" else [] deck_ene_list = [elem.split("_")[:2] for elem in soup.find(id="deck_ene")["value"].split("-")] \ if soup.find(id="deck_ene")["value"] != "" else [] # deck_ajs_list = [elem.split("_")[:2] for elem in soup.find(id="deck_ajs")["value"].split("-")]\ # if soup.find(id="deck_ajs")["value"] != "" else [] deck_list = deck_pke_list + deck_gds_list + deck_sup_list + deck_sta_list + deck_ene_list # + deck_ajs_list cards_to_print_count = 0 card_url_list = [] dl_counter = 0 for elm in deck_list: dl_counter += 1 pattern = re.compile(r"(/assets/images/card_images/([a-zA-Z]+)/[^\n]*/0+%s_[^\n]+\.jpg)" % elm[0], re.MULTILINE | re.DOTALL) match = pattern.search(card_data_script_text) if match: url = "https://www.pokemon-card.com" + match.group(1) elm.append(url) # print(elm) else: # たまに画像がなくて裏面の画像なことがあるので、その対応 url = "https://www.pokemon-card.com/assets/images/noimage/poke_ura.jpg" elm.append(url) try: for i in range(int(elm[1])): cards_to_print_count += 1 card_url_list.append(elm[2]) except ValueError: return HttpResponse( "デッキコードが正しくないか、ポケモンカード公式のサーバが応答していません。", content_type="text/plain; charset=utf-8" ) # キャンバスと出力ファイルの初期化 pdf = FPDF(orientation='P', unit='mm', format="A4") pdf.set_author("PTCG2Win") pdf.set_title(deck_code) pdf.set_subject("PDF to print") card_url_or_image_list = [] def split_images_and_append_to_list(input_image: Image.Image, x_pieces, y_pieces, output_list): imgwidth, imgheight = input_image.size height = imgheight // y_pieces width = imgwidth // x_pieces for j in range(y_pieces): for k in range(x_pieces): box = (k * width, j * height, (k + 1) * width, (j + 1) * height) part = input_image.crop(box) output_list.append(part) def trim(input_image: Image.Image) -> Image.Image: bg = Image.new(input_image.mode, input_image.size, input_image.getpixel((0, 0))) diff = ImageChops.difference(input_image, bg) diff = ImageChops.add(diff, diff, 2.0, -100) bbox = diff.getbbox() if bbox: return input_image.crop(bbox) v_union_filename_pattern: re.Pattern = re.compile(r"[A-Z]VUNION\.jpg$") reduced_card_url_list = [] cards_count = len(card_url_list) for i in range(cards_count): card_url = card_url_list[i] if re.search(v_union_filename_pattern, card_url): for j in range(card_url_list.count(card_url) // 4): reduced_card_url_list.append(card_url) card_url_list = ["" if url == card_url else url for url in card_url_list] else: reduced_card_url_list.append(card_url) filtered_card_url_list = [card_url for card_url in reduced_card_url_list if card_url != ""] for card_url in filtered_card_url_list: if "/card_images/legend/" in card_url: rsp = requests.get(card_url, stream=True) rsp.raw.decode_content = True img_object = Image.open(rsp.raw) img_object = img_object.rotate(90, expand=True) card_url_or_image_list.append(img_object) elif re.search(v_union_filename_pattern, card_url): rsp = requests.get(card_url, stream=True) rsp.raw.decode_content = True img_object = trim(Image.open(rsp.raw)) split_images_and_append_to_list(img_object, 2, 2, card_url_or_image_list) else: card_url_or_image_list.append(card_url) # ポケモンカードのサイズは63x88なので、紙を縦置きにした場合、3枚x3枚(189x264)入る。 for i in range(len(card_url_or_image_list)): card_url_or_image = card_url_or_image_list[i] # 9枚ごとに改ページ if i % 9 == 0: pdf.add_page("P") # print("Page", i // 9 + 1) # 3枚ごとに改行 x_pos = (11 + 63 * (i % 3)) y_pos = (15 + 88 * ((i % 9) // 3)) pdf.image( card_url_or_image, x_pos, y_pos, w=63, h=88, ) buffer = BytesIO() output = pdf.output() buffer.write(output) buffer.seek(0) # httpレスポンスの作成 return FileResponse(buffer, filename=f"{deck_code}.pdf", as_attachment=True, content_type='application/pdf')
def to_pdf(self, **kwargs): from fpdf import FPDF import random paper_format = kwargs.get('paper_format', 'a4') paper = self.PAPER_SIZES[string.lower(paper_format)] font_scale = kwargs.get('font_scale', 1) font_name = kwargs.get('font_name') colorize = kwargs.get('colorize', False) if font_name is not None and not colorize: self.generate_luminosity_mapping(font_name) orientation = kwargs.get('orientation') if self.im.width > self.im.height: orientation = 'l' else: orientation = 'p' if orientation == 'l': paper.width, paper.height = paper.height, paper.width inner = Size(ceil(paper.width - self.margins.left - self.margins.right), ceil(paper.height - self.margins.top - self.margins.bottom)) imgpixels = Size(self.im.width, self.im.height) scale = min(inner.width, inner.height) / max(imgpixels.width, imgpixels.height) offset = Point(self.margins.left + (inner.width - imgpixels.width * scale) / 2, self.margins.bottom + (inner.height - imgpixels.height * scale) / 2) pdf = FPDF(unit='mm', format=paper_format.upper(), orientation=orientation.upper()) pdf.set_compression(True) pdf.set_title('ASCII Art') pdf.set_author('Oliver Lau <*****@*****.**> - Heise Medien GmbH & Co. KG') pdf.set_creator('asciifier') pdf.set_keywords('retro computing art fun') pdf.add_page() if font_name is not None: pdf.add_font(font_name, fname=font_name, uni=True) else: font_name = 'Courier' pdf.set_font(font_name, '', mm2pt(scale * font_scale)) for y in range(0, self.im.height): yy = offset.y + scale * y for x in range(0, self.im.width): c = self.result[x][y] if c != ' ': if colorize is True: r, g, b = self.im.getpixel((x, y)) pdf.set_text_color(r, g, b) pdf.text(offset.x + x * scale, yy, random.choice(Asciifier.COLOR_CHARS)) else: pdf.text(offset.x + x * scale, yy, c) crop_area = Margin(offset.y - scale, offset.x + (self.im.width - 1 + font_scale) * scale, offset.y + (self.im.height - 2 + font_scale) * scale, offset.x) if kwargs.get('cropmarks', False): pdf.set_draw_color(0, 0, 0) pdf.set_line_width(pt2mm(0.1)) for p in [Point(crop_area.left, crop_area.top), Point(crop_area.right, crop_area.top), Point(crop_area.right, crop_area.bottom), Point(crop_area.left, crop_area.bottom)]: pdf.line(p.x - 6, p.y, p.x - 2, p.y) pdf.line(p.x + 2, p.y, p.x + 6, p.y) pdf.line(p.x, p.y - 6, p.x, p.y - 2) pdf.line(p.x, p.y + 2, p.x, p.y + 6) if kwargs.get('logo'): logo_width = 20 pdf.image(kwargs.get('logo'), x=(crop_area.right - crop_area.left - logo_width / 2) / 2, y=crop_area.bottom + 10, w=logo_width) return pdf.output(dest='S')
def to_pdf(self, **kwargs): from fpdf import FPDF import random paper_format = kwargs.get('paper_format', 'a4') paper = self.PAPER_SIZES[string.lower(paper_format)] font_scale = kwargs.get('font_scale', 1) font_name = kwargs.get('font_name') colorize = kwargs.get('colorize', False) if font_name is not None and not colorize: self.generate_luminosity_mapping(font_name) orientation = kwargs.get('orientation') if self.im.width > self.im.height: orientation = 'l' else: orientation = 'p' if orientation == 'l': paper.width, paper.height = paper.height, paper.width inner = Size( ceil(paper.width - self.margins.left - self.margins.right), ceil(paper.height - self.margins.top - self.margins.bottom)) imgpixels = Size(self.im.width, self.im.height) scale = min(inner.width, inner.height) / max(imgpixels.width, imgpixels.height) offset = Point( self.margins.left + (inner.width - imgpixels.width * scale) / 2, self.margins.bottom + (inner.height - imgpixels.height * scale) / 2) pdf = FPDF(unit='mm', format=paper_format.upper(), orientation=orientation.upper()) pdf.set_compression(True) pdf.set_title('ASCII Art') pdf.set_author('Oliver Lau <*****@*****.**> - Heise Medien GmbH & Co. KG') pdf.set_creator('asciifier') pdf.set_keywords('retro computing art fun') pdf.add_page() if font_name is not None: pdf.add_font(font_name, fname=font_name, uni=True) else: font_name = 'Courier' pdf.set_font(font_name, '', mm2pt(scale * font_scale)) for y in range(0, self.im.height): yy = offset.y + scale * y for x in range(0, self.im.width): c = self.result[x][y] if c != ' ': if colorize is True: r, g, b = self.im.getpixel((x, y)) pdf.set_text_color(r, g, b) pdf.text(offset.x + x * scale, yy, random.choice(Asciifier.COLOR_CHARS)) else: pdf.text(offset.x + x * scale, yy, c) crop_area = Margin( offset.y - scale, offset.x + (self.im.width - 1 + font_scale) * scale, offset.y + (self.im.height - 2 + font_scale) * scale, offset.x) if kwargs.get('cropmarks', False): pdf.set_draw_color(0, 0, 0) pdf.set_line_width(pt2mm(0.1)) for p in [ Point(crop_area.left, crop_area.top), Point(crop_area.right, crop_area.top), Point(crop_area.right, crop_area.bottom), Point(crop_area.left, crop_area.bottom) ]: pdf.line(p.x - 6, p.y, p.x - 2, p.y) pdf.line(p.x + 2, p.y, p.x + 6, p.y) pdf.line(p.x, p.y - 6, p.x, p.y - 2) pdf.line(p.x, p.y + 2, p.x, p.y + 6) if kwargs.get('logo'): logo_width = 20 pdf.image(kwargs.get('logo'), x=(crop_area.right - crop_area.left - logo_width / 2) / 2, y=crop_area.bottom + 10, w=logo_width) return pdf.output(dest='S')
""" Run this script to group the problems and solutions generated by the main.py script into a pdf. """ from fpdf import FPDF import os pdf = FPDF(orientation='P', unit='pt', format='A4') pdf.set_author('dinesh') pdf.set_title('python sudoku generator') """ Get all sudoku problem images from the problems/ directory """ files = list( map( lambda fn: 'problems/' + fn, sorted(os.listdir('problems/'), key=lambda name: int(name.split('.')[0])))) """ Draw the title at the top of the first page """ pdf.add_page() pdf.set_xy(0, 0) pdf.set_font('Arial', 'B', 90) pdf.cell(595, 250, "SUDOKU", 1, 0, 'C') pdf.set_xy(300, 150) pdf.set_font('Arial', 'B', 20) pdf.cell(295, 30, "©PySudokuGenerator", 0, 0, 'C') pdf.set_xy(300, 180) pdf.set_font('Arial', 'B', 10) pdf.cell(295, 10, "AUTHOR: DINESH RAM KUMAR", 0, 0, 'C') """ Draw the sudoku problems into the PDF 6 per page """ # Set the sudoku puzzle sizes w, h = 250, 250 sw, sh = 31, 23 # Size of empty space around sudoku puzzle
from fpdf import FPDF # Author: @NavonilDas pdf = FPDF() # Set Author Name of the PDF pdf.set_author("@NavonilDas") # Set Subject of The PDF pdf.set_subject("python") # Set the Title of the PDF pdf.set_title("Generating PDF with Python") pdf.add_page() # Set Font family Courier with font size 28 pdf.set_font("Courier", "", 18) # Add Text at (0,50) pdf.text(0, 50, "Example to generate PDF in python.") # Set Font Family Courier with italic and font size 28 pdf.set_font("Courier", "i", 28) pdf.text(0, 60, "This is an italic text") # Write text at 0,60 # Draw a Rectangle at (10,100) with Width 60,30 pdf.rect(10, 100, 60, 30, "D") # Set Fill color pdf.set_fill_color(255, 0, 0) # Red = (255,0,0) # Draw a Circle at (10,135) with diameter 50 pdf.ellipse(10, 135, 50, 50, "F")
from fpdf import FPDF pdf = FPDF(orientation='P', unit='mm', format='A4') pdf.add_page() # TEXTO pdf.set_font('Arial', '', 15) pdf.cell(w=0, h=15, txt='Hola mundo', border=1, ln=1, align='C', fill=0) pdf.cell(w=0, h=15, txt='Hola mundo', border=1, ln=2, align='C', fill=0) # METADATOS # titulo pdf.set_title(title='Hoja metadatos') # autor pdf.set_author(author='ALEX7320') # creador pdf.set_creator('Kodexam') # palabras clave pdf.set_keywords(keywords='Hoja, PDF, Prueba') # asunto pdf.set_subject(subject='Prueba de metadatos en PDF') pdf.output('hoja.pdf')
print("Warning: directory ", dest_path, " already exists, existing files may be overwritten") # Set up blank window #cv2.imshow("New code: ", np.zeros((100, 100), np.uint8)) start_time = dt.datetime.now() header_row = labels[0] headers = [x.strip() for x in header_row.split(',')] headers[0] = headers[0][3:] # For some reason there are a few extra characters in the first cell pdf = FPDF() pdf.set_compression(True) pdf.set_author("Mark Whitty @ UNSW") pdf.set_title(os.path.basename(input_filename)[:-4]) total_pages = len(labels) - 1 add_title_page(pdf, total_pages, os.path.basename(input_filename), headers) delimiter = "-" # Delimiter used between fields in machine readable code num_labels_generated = 0 # Generate output files based on labels for label in labels[1:]: split_values = [x.strip() for x in label.split(',')] machine_string = "" human_string = [] # Make machine readable content (no error checking done here on string lengths)
from fpdf import FPDF page_width = 210 page_height = 297 page_left_margin = 10 page_right_margin = 10 page_top_margin = 10 page_bottom_margin = 10 page_x_area = page_width - page_left_margin - page_right_margin page_y_area = page_height - page_top_margin - page_bottom_margin pdf = FPDF(orientation='P', unit='mm', format='A4') pdf.set_author("Author Test Terminal") pdf.set_creator("Creator Test Terminal") pdf.set_subject("Exam Results") pdf.add_page(orientation='P', format='A4', same=False) pdf.set_left_margin(margin=10) pdf.set_right_margin(margin=10) pdf.alias_nb_pages() # Draw border pdf.line(10, 10, 200, 10) pdf.line(10, 277, 200, 277) pdf.line(10, 10, 10, 277) pdf.line(200, 10, 200, 277)
from fpdf import FPDF pdf = FPDF() pdf.add_page() txt = input("Set author name: ") pdf.set_author(txt) filename = input("Set file name: ") pdf.set_font("Arial", size=12) print("Start typing, type /stop to save and exit") while True: line = input() if line == "/stop": break pdf.cell(200, 10, txt=line, ln=1, align="L") pdf.output(filename + ".pdf") print("file saved to ./" + filename + ".pdf")
class kut2fpdf(object): _document = None # Aquí se irán guardando los datos del documento logger = None _xml = None _xml_data = None _page_orientation = None _page_size = None _bottom_margin = None _left_margin = None _right_margin = None _top_margin = None _page_top = {} _data_row = None # Apunta a la fila actual en data _parser_tools = None _avalible_fonts = [] def __init__(self): self.logger = logging.getLogger("kut2rml") checkDependencies({"fpdf": "fpdf"}) from pineboolib.plugins.kugar.parsertools import parsertools self._parser_tools = parsertools() """ Convierte una cadena de texto que contiene el ".kut" en un pdf y retorna la ruta a este último. @param name. Nombre de ".kut". @param kut. Cadena de texto que contiene el ".kut". @param data. Cadena de texto que contiene los datos para ser rellenados en el informe. @return Ruta a fichero pdf. """ def parse(self, name, kut, data): try: self._xml = self._parser_tools.loadKut(kut) except Exception: self.logger.exception( "KUT2FPDF: Problema al procesar %s.kut", name) return False try: self._xml_data = load2xml(data) except Exception: self.logger.exception("KUT2FPDF: Problema al procesar xml_data") return False self.setPageFormat(self._xml) # self._page_orientation = # self._page_size = from fpdf import FPDF self._document = FPDF(self._page_orientation, "pt", self._page_size) # Seteamos rutas a carpetas con tipos de letra ... # Cargamos las fuentes disponibles for f in self._document.core_fonts: self.logger.debug("KUT2FPDF :: Adding font %s", f) self._avalible_fonts.append(f) self.newPage() self.processDetails() pdfname = pineboolib.project.getTempDir() pdfname += "/%s_%s.pdf" % (name, datetime.datetime.now().strftime("%Y%m%d%H%M%S")) # Datos del creador del documento self._document.set_title(name) self._document.set_author("Pineboo - kut2fpdf plugin") self._document.output(pdfname, 'F') return pdfname """ Indica el techo para calcular la posición de los objetos de esa sección. @return Número con el techo de la página actual. """ def topSection(self): return self._page_top[str(self._document.page_no())] """ Actualiza el valor del techo de la página actual. Se suele actualizar al procesar una sección. @param value. Numero que elspecifica el nuevo techo. """ def setTopSection(self, value): self._page_top[str(self._document.page_no())] = value """ Añade una nueva página al documento. """ def newPage(self): self._document.add_page(self._page_orientation) self._page_top[str(self._document.page_no())] = self._top_margin self._document.set_margins(self._left_margin, self._top_margin, self._right_margin) # Lo dejo pero no se nota nada # Corta con el borde inferior ... # self._document.set_auto_page_break( # True, self._document.h - self._bottom_margin) self.processSection("PageHeader") """ Procesa las secciones details con sus correspondientes detailHeader y detailFooter. """ def processDetails(self): # Procesamos la cabecera si procede .. prevLevel = 0 level = None for data in self._xml_data.findall("Row"): level = int(data.get("level")) if prevLevel > level: self.processData("DetailFooter", data, prevLevel) elif prevLevel < level: self.processData("DetailHeader", data, level) self.processData("Detail", data, level) prevLevel = level if level: for l in reversed(range(level + 1)): self.processData("DetailFooter", data, l) if self._xml.find("PageFooter"): self.processSection("PageFooter") elif self._xml.find("AddOnFooter"): self.processSection("AddOnFooter") """ Paso intermedio que calcula si detailHeader + detail + detailFooter entran en el resto de la ṕagina. Si no es así crea nueva página. @param section_name. Nombre de la sección a procesar. @param data. Linea de datos a procesar. @param data_level. Nivel de seccion. """ def processData(self, section_name, data, data_level): listDF = self._xml.findall(section_name) for dF in listDF: if dF.get("Level") == str(data_level): if section_name == "Detail" and (not dF.get("DrawIf") or data.get(dF.get("DrawIf"))): heightCalculated = self._parser_tools.getHeight(dF) + self.topSection() for dFooter in self._xml.findall("DetailFooter"): if dFooter.get("Level") == str(data_level): heightCalculated += self._parser_tools.getHeight(dFooter) pageFooter = self._xml.get("PageFooter") if pageFooter: if self._document.page_no() == 1 or pageFooter.get("PrintFrecuency") == "1": heightCalculated += self._parser_tools.getHeight(pageFooter) heightCalculated += self._bottom_margin if heightCalculated > self._document.h: # Si nos pasamos self.processSection("PageFooter") # Pie de página self.newPage() if not dF.get("DrawIf") or data.get(dF.get("DrawIf")): self.processXML(dF, data) #self.logger.debug("%s_BOTTON = %s" % (name.upper(), self.actualVSize[str(self.pagina)])) """ Procesa las secciones fuera de detail, pageHeader, pageFooter, AddOnFooter. @param name. Nombre de la sección a procesar. """ def processSection(self, name): sec_ = self._xml.find(name) if sec_: if sec_.get("PrintFrequency") == "1" or self._document.page_no() == 1: if sec_.tag == "PageFooter": self.setTopSection(self._document.h - int(sec_.get("Height"))) self.processXML(sec_) """ Procesa un elemento de xml. @param xml: El elemento a procesar. @param. data: Linea de datos afectada. """ def processXML(self, xml, data=None): fix_height = True if xml.tag == "DetailFooter": if xml.get("PlaceAtBottom") == "true": self.setTopSection(self.topSection() + self._parser_tools.getHeight(xml)) if xml.tag == "PageFooter": fix_height = False for child in xml.iter(): if child.tag in ("Label", "Field", "Special", "CalculatedField"): self.processText(child, data, fix_height) elif child.tag == "Line": self.processLine(child, fix_height) if xml.get("PlaceAtBottom") != "true": self.setTopSection(self.topSection() + self._parser_tools.getHeight(xml)) """ Procesa una linea. @param xml. Sección de xml a procesar. @param fix_height. Ajusta la altura a los .kut originales, excepto el pageFooter. """ def processLine(self, xml, fix_height=True): color = xml.get("Color") r = 0 if not color else int(color.split(",")[0]) g = 0 if not color else int(color.split(",")[1]) b = 0 if not color else int(color.split(",")[2]) #style = int(xml.get("Style")) width = int(xml.get("Width")) X1 = self.calculateLeftStart(xml.get("X1")) X2 = self.calculateRightEnd(xml.get("X2")) # Ajustar altura a secciones ya creadas Y1 = int(xml.get("Y1")) + self.topSection() Y2 = int(xml.get("Y2")) + self.topSection() if fix_height: Y1 = self._parser_tools.heightCorrection(Y1) Y2 = self._parser_tools.heightCorrection(Y2) self._document.set_line_width(width) self._document.set_draw_color(r, g, b) self._document.line(X1, Y1, X2, Y2) """ Comprueba si excedemos el margen izquierdo de la página actual @param x. Posición a comprobar. @return Valor corregido, si procede. """ def calculateLeftStart(self, x): x = int(x) ret_ = x if x < self._left_margin: ret_ = self._left_margin return ret_ """ Comprueba si excedemos el margen derecho de la página actual @param x. Posición a comprobar. @return Valor corregido, si procede. """ def calculateRightEnd(self, x): x = int(x) ret_ = x if x > (self._document.w - self._right_margin): ret_ = self._document.w - self._right_margin return ret_ """ Procesa una etiqueta. Esta peude ser un campo calculado, una etiqueta, un campo especial o una imagen. @param xml. Sección de xml a procesar. @param fix_height. Ajusta la altura a los .kut originales, excepto el pageFooter. """ def processText(self, xml, data_row=None, fix_height=True): isImage = False text = xml.get("Text") BorderWidth = int(xml.get("BorderWidth")) borderColor = xml.get("BorderColor") # x,y,W,H se calcula y corrigen aquí para luego estar correctos en los diferentes destinos posibles W = int(xml.get("Width")) H = self._parser_tools.getHeight(xml) x = int(xml.get("X")) y = int(xml.get("Y")) + self.topSection() # Añade la altura que hay ocupada por otras secciones if fix_height: y = self._parser_tools.heightCorrection(y) # Corrige la posición con respecto al kut original dataType = xml.get("Datatype") if xml.tag == "Field" and data_row is not None: text = data_row.get(xml.get("Field")) elif xml.tag == "Special": text = self._parser_tools.getSpecial( text[1:len(text) - 1], self._document.page_no()) elif xml.tag == "CalculatedField": if xml.get("FunctionName"): function_name = xml.get("FunctionName") try: nodo = self._parser_tools.convertToNode(data_row) text = str(pineboolib.project.call(function_name, [nodo])) except Exception: self.logger.exception( "KUT2FPDF:: Error llamando a function %s", function_name) return else: if data_row is None: data_row = self._xml_data[0] if xml.get("Field"): text = data_row.get( xml.get("Field")) if not "None" else "" if text and dataType is not None: text = self._parser_tools.calculated(text, int(dataType), xml.get("Precision"), data_row) if dataType == "5": isImage = True if text and text.startswith(filedir("../tempdata")): isImage = True precision = xml.get("Precision") negValueColor = xml.get("NegValueColor") Currency = xml.get("Currency") commaSeparator = xml.get("CommaSeparator") dateFormat = xml.get("DateFormat") if not isImage: self.drawText(x, y, W, H, xml, text) else: self.drawImage(x, y, W, H, xml, text) """ Dibuja un campo texto en la página. @param x. Pos x de la etiqueta. @param y. Pos y de la etiqueta. @param W. Anchura de la etiqueta. @param H. Altura de la etiqueta. @param xml. Sección del xml afectada. @param txt. Texto calculado de la etiqueta a crear. """ def drawText(self, x, y, W, H, xml, txt): if txt in ("None", None): return # Corregimos margenes: x = self.calculateLeftStart(x) W = self.calculateRightEnd(x + W) - x bg_color = xml.get("BackgroundColor").split(",") fg_color = xml.get("ForegroundColor").split(",") self._document.set_text_color(int(fg_color[0]), int(fg_color[1]), int(fg_color[2])) self._document.set_fill_color(int(bg_color[0]), int(bg_color[1]), int(bg_color[2])) if xml.get("BorderStyle") == "1": # FIXME: Hay que ajustar los margenes self.drawRect(x, y, W, H) #font_name, font_size, font_style font_style = "" font_size = int(xml.get("FontSize")) font_name = xml.get("FontFamily").lower() fontW = int(xml.get("FontWeight")) fontI = xml.get("FontItalic") fontU = xml.get("FontUnderlined") # FIXME: hay que ver si es así if fontW > 60 and font_size > 10: font_style += "B" if fontI == "1": font_style += "I" if fontU == "1": font_style += "U" while font_name not in self._avalible_fonts: font_found = self._parser_tools.find_font(font_name) if font_found: self.logger.info("KUT2FPDF::Añadiendo el tipo de letra %s (%s)", font_name, font_found) self._document.add_font(font_name, "", font_found, True) self._avalible_fonts.append(font_name) else: self.logger.warning("KUT2FPDF:: No se encuentra el tipo de letra %s. Sustituido por helvetica.", font_name) font_name = "helvetica" self._document.set_font(font_name, font_style, font_size) # Corregir alineación VAlignment = xml.get("VAlignment") # 0 izquierda, 1 centrado,2 derecha HAlignment = xml.get("HAlignment") if HAlignment == "1": # sobre X # Centrado x = x + (W / 2) - (self._document.get_string_width(txt) / 2) elif HAlignment == "2": # Derecha x = x + W - self._document.get_string_width(txt) else: # Izquierda x = x if VAlignment == "1": # sobre Y # Centrado y = (y + H / 2) + (self._document.font_size_pt / 2) elif VAlignment == "2": # Abajo y = y + W - font_size else: # Arriba y = y self._document.text(x, y, txt) """ Dibuja un cuadrado en la página actual. @param x. Pos x del cuadrado. @param y. Pos y del cuadrado. @param W. Anchura del cuadrado. @param H. Altura del cuadrado. """ def drawRect(self, x, y, W, H): self._document.rect(x, y, W, H, "DF") """ Inserta una imagen en la página actual. @param x. Pos x de la imagen. @param y. Pos y de la imagen. @param W. Anchura de la imagen. @param H. Altura de la imagen. @param xml. Sección del xml afectada. @param file_name. Nombr del fichero de tempdata a usar """ def drawImage(self, x, y, W, H, xml, file_name): self._document.image(file_name, x, y, W, H, "PNG") """ Define los parámetros de la página @param xml: Elemento xml con los datos del fichero .kut a procesar """ def setPageFormat(self, xml): custom_size = None self._bottom_margin = int(xml.get("BottomMargin")) self._left_margin = int(xml.get("LeftMargin")) self._right_margin = int(xml.get("RightMargin")) self._top_margin = int(xml.get("TopMargin")) page_size = int(xml.get("PageSize")) page_orientation = xml.get("PageOrientation") if page_size in [30, 31]: custom_size = [int(xml.get("CustomHeightMM")), int(xml.get("CustomWidthMM"))] self._page_orientation = "P" if page_orientation == "0" else "L" self._page_size = self._parser_tools.converPageSize( page_size, int(page_orientation), custom_size) # devuelve un array
from fpdf import FPDF # Author: @NavonilDas pdf = FPDF() # Set Author Name of the PDF pdf.set_author('@NavonilDas') # Set Subject of The PDF pdf.set_subject('python') # Set the Title of the PDF pdf.set_title('Generating PDF with Python') pdf.add_page() # Set Font family Courier with font size 28 pdf.set_font("Courier", '', 18) # Add Text at (0,50) pdf.text(0, 50, "Example to generate PDF in python.") # Set Font Family Courier with italic and font size 28 pdf.set_font("Courier", 'i', 28) pdf.text(0, 60, "This is an italic text") # Write text at 0,60 # Draw a Rectangle at (10,100) with Width 60,30 pdf.rect(10, 100, 60, 30, 'D') # Set Fill color pdf.set_fill_color(255, 0, 0) # Red = (255,0,0) # Draw a Circle at (10,135) with diameter 50 pdf.ellipse(10, 135, 50, 50, 'F')
def pdf_creator(data): '''receive some data and create a pdf report with a summary of information''' width = 210 today = date.today() pdf = FPDF() pdf.add_page() pdf.set_font('Arial', 'B', 16) # header display pdf.image('../images/germany_flag1.png') pdf.image('../images/header_pdf.png', 70, 10) #pdf.cell(f'Date: {today}') # descriptive text pdf.set_font('Arial', 'BU', 18) pdf.cell(0.1, 20, 'Data Resume:') pdf.set_font('Arial', 'BU', 12) pdf.cell(0.1, 40, f'Number of Houses:') pdf.set_font('Arial', size=12) pdf.cell(0.1, 55, f'{data.shape[0]} houses') pdf.set_font('Arial', 'BU', 12) pdf.cell(0.1, 70, f'Rent Price:') pdf.set_font('Arial', size=12) pdf.cell(0.1, 85, f'AVG - {data["montly_rent"].mean():.2f} EUR') pdf.cell(0.1, 95, f'MAX - {data["montly_rent"].max():.2f} EUR') pdf.cell(70, 105, f'MIN - {data["montly_rent"].min():.2f} EUR') pdf.set_font('Arial', 'BU', 12) pdf.cell(0.1, 70, 'Size:') pdf.set_font('Arial', size=12) pdf.cell(0.1, 85, f'AVG - {data["size"].mean():.2f}m²') pdf.cell(0.1, 95, f'MAX - {data["size"].max():.2f}m²') pdf.cell(60, 105, f'MIN - {data["size"].min():.2f}m²') pdf.set_font('Arial', 'BU', 12) pdf.cell(0.1, 70, 'Pets:') pdf.set_font('Arial', size=12) pdf.cell(0.1, 85, f'Not Allowed - {len(data[data["pets"] == "Pets not allowed"])} houses') pdf.cell(0.1, 95, f'Negotiable - {len(data[data["pets"] == "Pets negotiable"])} houses') pdf.cell(-132, 105, f'Allowed - {len(data[data["pets"] == "Pets allowed"])} houses') # histograms pdf.set_font('Arial', 'BU', 18) pdf.cell(0.1, 126, 'Data Histograms:') # first histplot hist_plot(data, 'montly_rent', 'MONTLY RENT') pdf.image('../images/montly_rent.png', 4, 126, width/2) # second histplot hist_plot(data, 'size', 'SIZE') pdf.image('../images/size.png', width/2, 126, width/2) # third histplot hist_plot(data, 'm2_value', 'M² VALUE') pdf.image('../images/m2_value.png', 4, 200, width/2) # fourth histplot hist_plot(data, 'pets', 'PETS') pdf.image('../images/pets.png', width/2, 200, width/2) # second page pdf.add_page() # header display pdf.image('../images/germany_flag1.png') pdf.image('../images/header_pdf.png', 70, 10) #==================== # graphs #==================== pdf.set_font('Arial', 'BU', 18) pdf.cell(0.1, 20, 'Data Graphs:') pdf.ln(20) montly_plot(data) pdf.image('../images/montly_rent_barplot.png', x=0, h=70) pdf.ln(5) m2_plot(data) pdf.image('../images/m2_barplot.png', x=0, h=70) pdf.ln(2) pet_plot(data) pdf.image('../images/pet_plot.png', x=25, h=55) pdf.set_author('Felipe Demenech Vasconcelos') pdf.close() pdf.output('../reports/rent_houses_germany.pdf', 'F') return pdf.output(dest='S')
def process(self, output_file_name=None, dpi=150, offset=0, fps=10, height_mm=50, margins=Margin(10, 10, 10, 10), paper_format='a4'): def draw_raster(): for ix in range(0, nx + 1): xx = x0 + ix * total.width pdf.line(xx, y0, xx, y1) if offset > 0 and ix != nx: pdf.line(xx + offset, y0, xx + offset, y1) for iy in range(0, ny + 1): yy = y0 + iy * total.height pdf.line(x0, yy, x1, yy) height_mm = float(height_mm) tmp_files = [] if self.clip: if fps != self.clip.fps: if self.verbosity > 0: print 'Transcoding from {} fps to {} fps ...'.format(self.clip.fps, fps) self.clip.write_videofile('tmp.mp4', fps=fps, audio=False) tmp_files.append('tmp.mp4') self.clip = VideoFileClip('tmp.mp4') self.fps = self.clip.fps self.frame_count = int(self.clip.duration * self.fps) clip_size = Size.from_tuple(self.clip.size) elif self.frames: clip_size = Size.from_tuple(self.im.size) paper = self.PAPER_SIZES[paper_format.lower()] printable_area = Size(paper.width - margins.left - margins.right, paper.height - margins.top - margins.bottom) frame_mm = Size(height_mm / clip_size.height * clip_size.width, height_mm) total = Size(offset + frame_mm.width, frame_mm.height) frame = Size(int(frame_mm.width / 25.4 * dpi), int(frame_mm.height / 25.4 * dpi)) nx = int(printable_area.width / total.width) ny = int(printable_area.height / total.height) if self.verbosity > 0: print 'Input: {} fps, {}x{}, {} frames'\ '\n from: {}'\ .format( self.fps, clip_size.width, clip_size.height, self.frame_count, self.input_file_name ) print 'Output: {}dpi, {}x{}, {:.2f}mm x {:.2f}mm, {}x{} tiles'\ '\n to: {}'\ .format( dpi, frame.width, frame.height, frame_mm.width, frame_mm.height, nx, ny, output_file_name ) pdf = FPDF(unit='mm', format=paper_format.upper(), orientation='L') pdf.set_compression(True) pdf.set_title('Funny video') pdf.set_author('Oliver Lau <*****@*****.**> - Heise Medien GmbH & Co. KG') pdf.set_creator('flippy') pdf.set_keywords('flip-book, video, animated GIF') pdf.set_draw_color(128, 128, 128) pdf.set_line_width(0.1) pdf.set_font('Helvetica', '', 12) pdf.add_page() i = 0 page = 0 tx, ty = -1, 0 x0, y0 = margins.left, margins.top x1, y1 = x0 + nx * total.width, y0 + ny * total.height if self.clip: all_frames = self.clip.iter_frames() elif self.frames: all_frames = AnimatedGif(self.im) else: all_frames = [] for f in all_frames: ready = float(i + 1) / self.frame_count if self.verbosity: sys.stdout.write('\rProcessing frames |{:30}| {}%' .format('X' * int(30 * ready), int(100 * ready))) sys.stdout.flush() tx += 1 if type(f) == GifImagePlugin.GifImageFile: f.putpalette(self.palette) self.last_im.paste(f) im = self.last_im.convert('RGBA') else: im = Image.fromarray(f) im.thumbnail(frame.to_tuple()) if tx == nx: tx = 0 ty += 1 if ty == ny: ty = 0 draw_raster() pdf.add_page() page += 1 temp_file = 'tmp-{}-{}-{}.jpg'.format(page, tx, ty) im.save(temp_file) tmp_files.append(temp_file) x = x0 + tx * total.width y = y0 + ty * total.height pdf.image(temp_file, x=x + offset, y=y, w=frame_mm.width, h=frame_mm.height) text = Point(x, y + frame_mm.height - 2) if offset > 0: pdf.rotate(90, text.x, text.y) pdf.text(text.x, text.y + 5, '{}'.format(i)) pdf.rotate(0) i += 1 if y != 0 and x != 0: draw_raster() if self.verbosity > 0: print '\nGenerating PDF ...' pdf.output(name=output_file_name) if self.verbosity > 0: print 'Removing temporary files ...' for temp_file in tmp_files: os.remove(temp_file)
from fpdf import FPDF # Author: @ChrisChou pdf = FPDF() # Set Author Name of the PDF pdf.set_author('@ChrisChou') # Set Subject of The PDF pdf.set_subject('pdf') # Set the Title of the PDF pdf.set_title('Create PDF with Python') pdf.add_page() # Set Font family Courier with font size 28 pdf.set_font("Courier", '', 20) # Add Text at (0,50) pdf.text(0, 50, "Example to make PDF with python.") # Set Font Family Courier with italic and font size 28 pdf.set_font("Courier", 'i', 28) pdf.text(0, 60, "This is an italic text") # Write text at 0,60 # Draw a Rectangle at (10,100) with Width 60,30 pdf.rect(10, 100, 60, 30, 'D') # Set Fill color pdf.set_fill_color(255, 0, 0) # Red = (255,0,0) # Draw a Circle at (10,135) with diameter 50 pdf.ellipse(10, 135, 50, 50, 'F')
elif res[0] == 5: output = 'Pigmented Benign Keratosis' about = "Pigmented actinic keratosis is a variant of actinic keratosis that occurs less commonly. In contrast to presenting as an erythematous plaque, its appearance can mimic a pigmented lesion (lentigo maligna or solar lentigo) or a keratinocytic lesion (lichen planus-like keratosis)." elif res[0] == 6: output = 'Seborrheic Keratosis' about = 'A seborrheic keratosis is a non-cancerous (benign) skin tumour that originates from cells in the outer layer of the skin. Like liver spots, seborrheic keratoses are seen more often as people age.The tumours (also called lesions) appear in various colours, from light tan to black. They are round or oval, feel flat or slightly elevated, like the scab from a healing wound, and range in size from very small to more than 2.5 centimetres (1 in) across. They can often come in association with other skin conditions, including basal cell carcinoma. Rarely seborrheic keratosis and basal cell carcinoma occur at the same location. At clinical examination the differential diagnosis includes warts and melanoma.' elif res[0] == 7: output = 'Squamous Cell Carcinoma' about = 'Squamous cell carcinomas (SCCs), also known as epidermoid carcinomas, comprise a number of different types of cancer that result from squamous cells. These cells form on the surface of the skin, on the lining of hollow organs in the body, and on the lining of the respiratory and digestive tracts.Common types include:\n\nSquamous cell skin cancer: A type of skin cancer\nSquamous-cell carcinoma of the lung: A type of lung cancer\nSquamous cell thyroid carcinoma: A type of thyroid cancer\nEsophageal squamous cell carcinoma: A type of esophageal cancer\nSquamous-cell carcinoma of the v****a: A type of vaginal cancerDespite sharing the name "squamous cell carcinoma", the SCCs of different body sites can show differences in their presented symptoms, natural history, prognosis, and response to treatment.' elif res[0] == 8: output = 'Vascular Lesion' about = 'A skin condition, also known as cutaneous condition, is any medical condition that affects the integumentary system—the organ system that encloses the body and includes skin, hair, nails, and related muscle and glands. The major function of this system is as a barrier against the external environment.Conditions of the human integumentary system constitute a broad spectrum of diseases, also known as dermatoses, as well as many nonpathologic states (like, in certain circumstances, melanonychia and racquet nails). While only a small number of skin diseases account for most visits to the physician, thousands of skin conditions have been described. Classification of these conditions often presents many nosological challenges, since underlying causes and pathogenetics are often not known. Therefore, most current textbooks present a classification based on location (for example, conditions of the mucous membrane), morphology (chronic blistering conditions), cause (skin conditions resulting from physical factors), and so on.Clinically, the diagnosis of any particular skin condition is made by gathering pertinent information regarding the presenting skin lesion(s), including the location (such as arms, head, legs), symptoms (pruritus, pain), duration (acute or chronic), arrangement (solitary, generalized, annular, linear), morphology (macules, papules, vesicles), and color (red, blue, brown, black, white, yellow).' pdf = FPDF(orientation='P', unit='mm', format='A4') pdf.set_title('Report') pdf.add_page() pdf.set_author('Smart Doctor') pdf.set_font("Arial", size=15) pdf.multi_cell(200, 10, txt="Medical Report", align='C', border=1) x = datetime.datetime.now() pdf.multi_cell(200, 10, txt=str(x), align='R') pdf.multi_cell(200, 10, txt='Dear Sir,', align='L') pdf.multi_cell( 200, 10, txt=f'According to our prediction , you are sufferring from {output}\n', align='C') pdf.multi_cell(200, 10, txt='About the Disease', align='C') pdf.multi_cell(200, 10, txt=about, align='J') pdf.multi_cell(200, 10, txt='Our Suggestion for you ', align='C') if output == 'Actinic Keratosis': fr = open("/root/skincancer/Actinic keratosis.txt", "r")
def prepare_report(): """ Master method, creates a folder with the user's desired filename, and writes a PDF report with salient information. Also creates a line chart and a bar chart! :return: Nothing. """ # Get list of folders in user's desired directory. Check to make sure that they entered valid information. try: local_list = os.listdir(report_dest) except NotADirectoryError: print("Wrong Directory Specification.") quit() # Setting final destination of the report. global final_destination final_destination = Path(report_dest + "REPORT/") # Checking to make sure that we are able to create a folder at the user's desired filepath. # If invalid, program quits. if local_list.count("REPORT") == 0: try: os.mkdir(final_destination) except FileNotFoundError: print("Incorrect filepath.") quit() # Begin writing to PDF. pdf = FPDF(orientation="P", unit='cm', format="Letter") pdf.set_font('Arial') pdf.set_author("Chris Matthew Cyril") pdf.set_font_size(12) pdf.add_page(orientation="P") pdf.set_title(title="REPORT") pdf.write(h=0, txt='GENERATED REPORT -- ' + str(datetime.datetime.now())) pdf.write(h=1, txt="\nDataBank source was found in: " + DataBank_source) pdf.write(h=1, txt="\nBMAL Filepath: " + BMAL_filepath) pdf.write(h=1, txt="\nCYCLE Filepath: " + CYC_filepath) pdf.write(h=1, txt="\nThis report can be found at: " + str(final_destination)) pdf.set_text_color(0, 255, 255) pdf.write( h=1, txt="\nGitHub Link To Code", link="https://github.com/ChrisMatthewCyril/Needleman/tree/Version3.0") pdf.set_text_color(0, 0, 0) pdf.write(h=1, txt="\nCalculated Gene Deviation Score: " + str(gene_deviation_score)) pdf.write(h=1, txt="\n Number of Gene pairs: " + str(num_pairs)) pdf.add_page(orientation="P") pdf.set_font('Arial', style='B') pdf.cell(w=14, h=1, txt="Compared Files", border=1, ln=0, align='L', fill=False) pdf.cell(w=6, h=1, txt="Needleman-Wunsch Score", border=1, ln=1, align='L', fill=False) pdf.set_font('Arial', style='') # Making table of gene pairings with alignment scores. for first_file, second_file in gene_pair_scores: pdf.cell(w=14, h=1, txt=first_file + " vs " + second_file, border=1, ln=0, align='L', fill=False) pdf.cell(w=6, h=1, txt=str(gene_pair_scores[(first_file, second_file)]), border=1, ln=1, align='R', fill=False) # Making bar and line charts. barchart_path = plot_bar() linechart_path = plot_line() # Adding the bar and line chart images from their links on the computer. pdf.add_page(orientation='landscape') pdf.image(barchart_path, h=20, w=27) pdf.image(linechart_path, h=20, w=27) pdf.add_page(orientation='portrait') pdf.write( h=1, txt="Thanks for an amazing quarter, Professor Schiffer and the TA's!\n" "Best, as always,\nChris Matthew Cyril :)") pdf.add_page(orientation='portrait') # pdf.write(h=1, txt=getAnalysis()) pdf_location = final_destination / report_filename pdf.output(str(pdf_location) + ".pdf", dest='F').encode('latin-1') # Thank you! Close-out message. print("Thanks for an amazing quarter, Professor Schiffer and the TA's!\n" "Best, as always,\nChris Matthew Cyril :) \n" "Don't forget to pick up your report! You can find it at: " + str(pdf_location))
def generate_raport(name, rank_solo, rank_flex, server, lvl, chest_champs): """ This functions is like template: takes arguments and generate pdfs from the data, should be written more simply """ pdf = FPDF() pdf.set_author("Marcin Binkowski") pdf.add_page() pdf.set_font("arial", size=50) pdf.cell(0, 20, txt="GraphsLeague", ln=2, align="C") pdf.set_font("arial", size=30) pdf.image("../src/temporary/icon.png", w=30) pdf.cell(0, 15, txt="{}".format(name), ln=2, align="L") pdf.set_font( "arial", "B", size=16, ) pdf.cell(200, 8, txt="server: {}".format(server), ln=1, align="L") pdf.cell(200, 8, txt="level: {}".format(lvl), ln=1, align="L") pdf.cell(200, 30, ln=1, align="L") try: pdf.image("../src/icons/base-icons/{}.png".format(rank_solo), w=50, x=60, y=70) except: pdf.image("../src/icons/base-icons/provisional.png".format(rank_solo), w=50, x=60, y=70) try: pdf.image("../src/icons/base-icons/{}.png".format(rank_flex), w=50, x=125, y=70) except: pdf.image("../src/icons/base-icons/provisional.png".format(rank_solo), w=50, x=125, y=70) pdf.set_font("arial", size=24) pdf.cell(90, 8, txt="Ranked", ln=0, align="R") pdf.cell(100, 8, txt="Flex", ln=1, align="C") pdf.cell(200, 8, ln=1, align="C") pdf.image("../src/temporary/{}_mastery_distribution.png".format(name), w=90, x=0) try: pdf.image("../src/temporary/top_champ2.png", w=25, x=100, y=160) except: pass try: pdf.image("../src/temporary/top_champ1.png", w=30, x=127, y=155) except: pass try: pdf.image("../src/temporary/top_champ3.png", w=20, x=159, y=165) except: pass try: pdf.image("../src/temporary/{}_solo_duo.png".format(name), w=110, x=2, y=195) except: pdf.image("../src/temporary/blank_graph.png".format(name), w=110, x=2, y=195) try: pdf.image("../src/temporary/{}_flex.png".format(name), w=110, x=98, y=195) except: pdf.image("../src/temporary/blank_graph.png".format(name), w=110, x=98, y=195) pdf.cell(200, 60, ln=1) pdf.set_font("Courier", size=12) pdf.cell(200, 8, txt="You can still get chests for playing: {}, {} and {}".format( chest_champs[0], chest_champs[1], chest_champs[2]), ln=1, align="L") pdf.output("../raports/{}_raport.pdf".format(name))
def process( self, output_file_name=None, dpi=150, offset=0, fps=10, height_mm=50, margins=Margin(10, 10, 10, 10), paper_format="a4", ): def draw_raster(): for ix in range(0, nx + 1): xx = x0 + ix * total.width pdf.line(xx, y0, xx, y1) if offset > 0 and ix != nx: pdf.line(xx + offset, y0, xx + offset, y1) for iy in range(0, ny + 1): yy = y0 + iy * total.height pdf.line(x0, yy, x1, yy) height_mm = float(height_mm) tmp_files = [] if self.clip: if fps != self.clip.fps: if self.verbosity > 0: print "Transcoding from {} fps to {} fps ...".format(self.clip.fps, fps) self.clip.write_videofile("tmp.mp4", fps=fps, audio=False) tmp_files.append("tmp.mp4") self.clip = VideoFileClip("tmp.mp4") self.fps = self.clip.fps self.frame_count = int(self.clip.duration * self.fps) clip_size = Size.from_tuple(self.clip.size) elif self.frames: clip_size = Size.from_tuple(self.im.size) paper = self.PAPER_SIZES[paper_format.lower()] printable_area = Size(paper.width - margins.left - margins.right, paper.height - margins.top - margins.bottom) frame_mm = Size(height_mm / clip_size.height * clip_size.width, height_mm) total = Size(offset + frame_mm.width, frame_mm.height) frame = Size(int(frame_mm.width / 25.4 * dpi), int(frame_mm.height / 25.4 * dpi)) nx = int(printable_area.width / total.width) ny = int(printable_area.height / total.height) if self.verbosity > 0: print "Input: {} fps, {}x{}, {} frames" "\n from: {}".format( self.fps, clip_size.width, clip_size.height, self.frame_count, self.input_file_name ) print "Output: {}dpi, {}x{}, {:.2f}mm x {:.2f}mm, {}x{} tiles" "\n to: {}".format( dpi, frame.width, frame.height, frame_mm.width, frame_mm.height, nx, ny, output_file_name ) pdf = FPDF(unit="mm", format=paper_format.upper(), orientation="L") pdf.set_compression(True) pdf.set_title("Funny video") pdf.set_author("Oliver Lau <*****@*****.**> - Heise Medien GmbH & Co. KG") pdf.set_creator("flippy") pdf.set_keywords("flip-book, video, animated GIF") pdf.set_draw_color(128, 128, 128) pdf.set_line_width(0.1) pdf.set_font("Helvetica", "", 12) pdf.add_page() i = 0 page = 0 tx, ty = -1, 0 x0, y0 = margins.left, margins.top x1, y1 = x0 + nx * total.width, y0 + ny * total.height if self.clip: all_frames = self.clip.iter_frames() elif self.frames: all_frames = AnimatedGif(self.im) else: all_frames = [] for f in all_frames: ready = float(i + 1) / self.frame_count if self.verbosity: sys.stdout.write("\rProcessing frames |{:30}| {}%".format("X" * int(30 * ready), int(100 * ready))) sys.stdout.flush() tx += 1 if type(f) == GifImagePlugin.GifImageFile: f.putpalette(self.palette) self.last_im.paste(f) im = self.last_im.convert("RGBA") else: im = Image.fromarray(f) im.thumbnail(frame.to_tuple()) if tx == nx: tx = 0 ty += 1 if ty == ny: ty = 0 draw_raster() pdf.add_page() page += 1 temp_file = "tmp-{}-{}-{}.jpg".format(page, tx, ty) im.save(temp_file) tmp_files.append(temp_file) x = x0 + tx * total.width y = y0 + ty * total.height pdf.image(temp_file, x=x + offset, y=y, w=frame_mm.width, h=frame_mm.height) text = Point(x, y + frame_mm.height - 2) if offset > 0: pdf.rotate(90, text.x, text.y) pdf.text(text.x, text.y + 5, "{}".format(i)) pdf.rotate(0) i += 1 if y != 0 and x != 0: draw_raster() if self.verbosity > 0: print "\nGenerating PDF ..." pdf.output(name=output_file_name) if self.verbosity > 0: print "Removing temporary files ..." for temp_file in tmp_files: os.remove(temp_file)