def CreatePdfNum(self,s,num): x = 0 salt = ''.join(random.sample(string.ascii_letters + string.digits, 16)) #pdfmetrics.registerFont(TTFont('hei', 'hei.TTF')) #import testSubFun #testSubFun.testSubFunc('first') #设置页面大小 c = canvas.Canvas('Result\\dlp%s.pdf' % num,pagesize=A4) xlength,ylength = A4 #print('width:%d high:%d'%(xlength,ylength)) #c.line(1,1,ylength/2,ylength) #设置文字类型及字号 #c.setFont('hei',20) #生成一个table表格 atable = [[1,2,3,4,5,6,7,8],[11,12,13,14,15,16,17,18]] t = Table(atable,50,20) t.setStyle(TableStyle([('ALIGN',(0,0),(3,1),'CENTER'), ('INNERGRID',(0,0),(-1,-1),0.25,colors.black), ('BOX',(0,0),(-1,-1),0.25,colors.black)])) textOb = c.beginText(1,ylength-10) indexVlaue = 0 while(indexVlaue < ylength): textStr = u'''wo shi tupian---wo shi tupian--wo shi tupian--wo shi tupian%d'''%indexVlaue + salt #print('nextline,nextline%d'%indexVlaue) textOb.textLine(textStr) indexVlaue = indexVlaue + 1 break c.drawText(textOb) #简单的图片载入 imageValue = 'file\\dlp.png' c.drawImage(imageValue,97,97,650,650) #c.drawImage('file\\dlp.png',50,50,50,50) t.split(0,0) t.drawOn(c,100,1) c.showPage() #换页的方式不同的showPage while x < s: imageValue = 'file\\dlp.png' c.drawImage(imageValue,97,97,650,650) c.drawString(0,0,'tupian%s' % x) c.showPage() x = x + 1 c.save()
def draw_course_info(self, y_pos): """ Draws the main table containing the data items. """ course_items_data = [[ '', (_('Description')), (_('Quantity')), (_('List Price\nper item')), (_('Discount\nper item')), (_('Amount')), '' ]] for row_item in self.items_data: course_items_data.append([ '', Paragraph(row_item['item_description'], getSampleStyleSheet()['Normal']), row_item['quantity'], '{list_price:.2f} {currency}'.format( list_price=row_item['list_price'], currency=self.currency), '{discount:.2f} {currency}'.format( discount=row_item['discount'], currency=self.currency), '{item_total:.2f} {currency}'.format( item_total=row_item['item_total'], currency=self.currency), '' ]) padding_width = 7 * mm desc_col_width = 60 * mm qty_col_width = 26 * mm list_price_col_width = 21 * mm discount_col_width = 21 * mm amount_col_width = 40 * mm course_items_table = Table(course_items_data, [ padding_width, desc_col_width, qty_col_width, list_price_col_width, discount_col_width, amount_col_width, padding_width ], splitByRow=1, repeatRows=1) course_items_table.setStyle( TableStyle([ #List Price, Discount, Amount data items ('ALIGN', (3, 1), (5, -1), 'RIGHT'), # Amount header ('ALIGN', (5, 0), (5, 0), 'RIGHT'), # Amount column (header + data items) ('RIGHTPADDING', (5, 0), (5, -1), 7 * mm), # Quantity, List Price, Discount header ('ALIGN', (2, 0), (4, 0), 'CENTER'), # Description header ('ALIGN', (1, 0), (1, -1), 'LEFT'), # Quantity data items ('ALIGN', (2, 1), (2, -1), 'CENTER'), # Lines below the header and at the end of the table. ('LINEBELOW', (0, 0), (-1, 0), 1.00, '#cccccc'), ('LINEBELOW', (0, -1), (-1, -1), 1.00, '#cccccc'), # Innergrid around the data rows. ('INNERGRID', (1, 1), (-2, -1), 0.50, '#cccccc'), # Entire table ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), ('TOPPADDING', (0, 0), (-1, -1), 2 * mm), ('BOTTOMPADDING', (0, 0), (-1, -1), 2 * mm), ('TEXTCOLOR', (0, 0), (-1, -1), colors.black), ])) rendered_width, rendered_height = course_items_table.wrap(0, 0) table_left_padding = (self.page_width - rendered_width) / 2 split_tables = course_items_table.split( 0, self.first_page_available_height) if len(split_tables) > 1: # The entire Table won't fit in the available space and requires splitting. # Draw the part that can fit, start a new page # and repeat the process with the rest of the table. split_table = split_tables[0] __, rendered_height = split_table.wrap(0, 0) split_table.drawOn(self.pdf, table_left_padding, y_pos - rendered_height) self.prepare_new_page() split_tables = split_tables[1].split( 0, self.second_page_available_height) while len(split_tables) > 1: split_table = split_tables[0] __, rendered_height = split_table.wrap(0, 0) split_table.drawOn( self.pdf, table_left_padding, self.second_page_start_y_pos - rendered_height) self.prepare_new_page() split_tables = split_tables[1].split( 0, self.second_page_available_height) split_table = split_tables[0] __, rendered_height = split_table.wrap(0, 0) split_table.drawOn(self.pdf, table_left_padding, self.second_page_start_y_pos - rendered_height) else: # Table will fit without the need for splitting. course_items_table.drawOn(self.pdf, table_left_padding, y_pos - rendered_height) if not self.is_on_first_page(): y_pos = self.second_page_start_y_pos return y_pos - rendered_height - self.min_clearance
class DelayedTable(Table): """A flowable that inserts a table for which it has the data. Needed so column widths can be determined after we know on what frame the table will be inserted, thus making the overal table width correct. """ def __init__(self, data, colWidths, style=None, repeatrows=False, splitByRow=True): self.data = data self._colWidths = colWidths if style is None: style = TableStyle([ ('LEFTPADDING', (0, 0), (-1, -1), 0), ('RIGHTPADDING', (0, 0), (-1, -1), 0), ('TOPPADDING', (0, 0), (-1, -1), 0), ('BOTTOMPADDING', (0, 0), (-1, -1), 0), ]) self.style = style self.t = None self.repeatrows = repeatrows self.hAlign = TA_CENTER self.splitByRow = splitByRow def wrap(self, w, h): # Create the table, with the widths from colWidths reinterpreted # if needed as percentages of frame/cell/whatever width w is. # _tw = w/sum(self.colWidths) def adjust(*args, **kwargs): kwargs['total'] = w return styles.adjustUnits(*args, **kwargs) # adjust=functools.partial(styles.adjustUnits, total=w) self.colWidths = [adjust(x) for x in self._colWidths] # colWidths = [_w * _tw for _w in self.colWidths] self.t = Table( self.data, colWidths=self.colWidths, style=self.style, repeatRows=self.repeatrows, splitByRow=True, ) # splitByRow=self.splitByRow) self.t.hAlign = self.hAlign return self.t.wrap(w, h) def split(self, w, h): if self.splitByRow: if not self.t: self.wrap(w, h) return self.t.split(w, h) else: return [] def drawOn(self, canvas, x, y, _sW=0): self.t.drawOn(canvas, x, y, _sW) def identity(self, maxLen=None): return "<%s at %s%s%s> containing: %s" % ( self.__class__.__name__, hex(id(self)), self._frameName(), getattr(self, 'name', '') and (' name="%s"' % getattr(self, 'name', '')) or '', repr(self.data[0]), )[:180]
def draw_course_info(self, y_pos): """ Draws the main table containing the data items. """ course_items_data = [ ['', (_('Description')), (_('Quantity')), (_('List Price\nper item')), (_('Discount\nper item')), (_('Amount')), ''] ] for row_item in self.items_data: course_items_data.append([ '', Paragraph(row_item['item_description'], getSampleStyleSheet()['Normal']), row_item['quantity'], '{currency}{list_price:.2f}'.format(list_price=row_item['list_price'], currency=self.currency), '{currency}{discount:.2f}'.format(discount=row_item['discount'], currency=self.currency), '{currency}{item_total:.2f}'.format(item_total=row_item['item_total'], currency=self.currency), '' ]) padding_width = 7 * mm desc_col_width = 60 * mm qty_col_width = 26 * mm list_price_col_width = 21 * mm discount_col_width = 21 * mm amount_col_width = 40 * mm course_items_table = Table( course_items_data, [ padding_width, desc_col_width, qty_col_width, list_price_col_width, discount_col_width, amount_col_width, padding_width ], splitByRow=1, repeatRows=1 ) course_items_table.setStyle(TableStyle([ #List Price, Discount, Amount data items ('ALIGN', (3, 1), (5, -1), 'RIGHT'), # Amount header ('ALIGN', (5, 0), (5, 0), 'RIGHT'), # Amount column (header + data items) ('RIGHTPADDING', (5, 0), (5, -1), 7 * mm), # Quantity, List Price, Discount header ('ALIGN', (2, 0), (4, 0), 'CENTER'), # Description header ('ALIGN', (1, 0), (1, -1), 'LEFT'), # Quantity data items ('ALIGN', (2, 1), (2, -1), 'CENTER'), # Lines below the header and at the end of the table. ('LINEBELOW', (0, 0), (-1, 0), 1.00, '#cccccc'), ('LINEBELOW', (0, -1), (-1, -1), 1.00, '#cccccc'), # Innergrid around the data rows. ('INNERGRID', (1, 1), (-2, -1), 0.50, '#cccccc'), # Entire table ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), ('TOPPADDING', (0, 0), (-1, -1), 2 * mm), ('BOTTOMPADDING', (0, 0), (-1, -1), 2 * mm), ('TEXTCOLOR', (0, 0), (-1, -1), colors.black), ])) rendered_width, rendered_height = course_items_table.wrap(0, 0) table_left_padding = (self.page_width - rendered_width) / 2 split_tables = course_items_table.split(0, self.first_page_available_height) if len(split_tables) > 1: # The entire Table won't fit in the available space and requires splitting. # Draw the part that can fit, start a new page # and repeat the process with the rest of the table. split_table = split_tables[0] __, rendered_height = split_table.wrap(0, 0) split_table.drawOn(self.pdf, table_left_padding, y_pos - rendered_height) self.prepare_new_page() split_tables = split_tables[1].split(0, self.second_page_available_height) while len(split_tables) > 1: split_table = split_tables[0] __, rendered_height = split_table.wrap(0, 0) split_table.drawOn(self.pdf, table_left_padding, self.second_page_start_y_pos - rendered_height) self.prepare_new_page() split_tables = split_tables[1].split(0, self.second_page_available_height) split_table = split_tables[0] __, rendered_height = split_table.wrap(0, 0) split_table.drawOn(self.pdf, table_left_padding, self.second_page_start_y_pos - rendered_height) else: # Table will fit without the need for splitting. course_items_table.drawOn(self.pdf, table_left_padding, y_pos - rendered_height) if not self.is_on_first_page(): y_pos = self.second_page_start_y_pos return y_pos - rendered_height - self.min_clearance
print('width:%d high:%d' % (xlength, ylength)) #c.line(1,1,ylength/2,ylength) #设置文字类型及字号 c.setFont('hei', 20) #生成一个table表格 atable = [[1, 2, 3, 4], [5, 6, 7, 8]] t = Table(atable, 50, 20) t.setStyle( TableStyle([('ALIGN', (0, 0), (3, 1), 'CENTER'), ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black), ('BOX', (0, 0), (-1, -1), 0.25, colors.black)])) textOb = c.beginText(1, ylength - 10) indexVlaue = 0 while (indexVlaue < ylength): textStr = '''test 中文写入测试中文写入测试中文写入测试中文写入测试%d''' % indexVlaue #print('nextline,nextline%d'%indexVlaue) textOb.textLine(textStr) indexVlaue = indexVlaue + 1 break c.drawText(textOb) #简单的图片载入 imageValue = 'test.png' c.drawImage(imageValue, 97, 97, 300, 300) c.drawImage('test.png', 50, 50, 50, 50) t.split(0, 0) t.drawOn(c, 100, 1) c.showPage() #换页的方式不同的showPage c.drawString(0, 0, 'helloword') c.showPage()
def pdf(group, username, list, show_header=True, show_footer=True): """PDF version of list""" content = BytesIO() columns = list.column_set.all() accounts = list.accounts() margin = 0.5 * cm font_name = "Times-Roman" font_name_bold = "Times-Bold" font_size = 12 font_size_small = 10 font_size_min = 8 head_height = 30 # pt foot_height = 15 # pt logo_height = 25 # pt font_size_name = font_size_small font_size_short_name = font_size_small font_size_balance = font_size_small if list.orientation == list.LANDSCAPE: height, width = A4 else: width, height = A4 grid_style = TableStyle(parent=GRID_STYLE) # Create canvas for page and set fonts p = canvas.Canvas(content, (width, height)) show_logo = bool(group.logo and group.logo.storage.exists(group.logo.path)) if show_logo: # Find scaling ratio ratio = group.logo.width / group.logo.height # Load logo with correct scaling logo = Image( group.logo.path, width=logo_height * ratio, height=logo_height ) def draw_header(): if not show_header: return if show_logo: logo.drawOn( p, width - margin - logo_height * ratio, height - margin - logo_height, ) # Setup rest of header p.setFont(font_name, font_size) p.drawString( margin, height - margin - font_size, f"{group}: {list.name}" ) p.setFont(font_name, font_size_small) p.drawString( margin, height - margin - font_size - font_size + 2, "%s: %s %s %s" % (_("Printed"), str(date.today()), _("by"), username), ) footer = [] if group.email: footer.append(group.email) if group.account_number: footer.append(group.get_account_number_display()) if list.comment.strip(): footer.append(list.comment.replace("\n", " ").replace("\r", " ")) def draw_footer(): if not show_footer: return p.drawString(margin, margin, " - ".join(footer)) blacklisted_note = _("Blacklisted accounts are marked with: ") p.drawRightString(width - margin - 10, margin, blacklisted_note) p.setFillColor(BLACKLISTED_COLOR) p.rect(width - margin - 10, margin, 8, 8, fill=1, stroke=0) p.setFont(font_name, font_size) if not accounts: no_accounts_message = _("Sorry, this list is empty.") draw_header() p.drawString( margin, height - font_size - margin - head_height, no_accounts_message, ) draw_footer() p.save() return content elif not columns: no_columns_message = _( "Sorry, this list isn't set up correctly, " "please add some columns." ) draw_header() p.drawString( margin, height - font_size - margin - head_height, no_columns_message, ) draw_footer() p.save() return content # Store col widths col_width = [] header = [_("Name")] if list.account_width: col_width.append(list.account_width) if list.short_name_width: col_width.append(list.short_name_width) if list.account_width and list.short_name_width: header.append("") if list.balance_width: header.append(_("Balance")) col_width.append(list.balance_width) if list.short_name_width > 0 and list.account_width > 0: grid_style.add("SPAN", (0, 0), (1, 0)) base_x = len(header) for c in columns: header.append(c.name) col_width.append(c.width) # Calculate relative col widths over to absolute points for i, w in enumerate(col_width): col_width[i] = ( float(w) / float( (list.listcolumn_width or 0) + list.balance_width + (list.account_width or 0) + (list.short_name_width or 0) ) * (width - 2 * margin) ) # Intialise table with header data = [header] for i, a in enumerate(accounts): color = ALTERNATE_COLORS[(i + 1) % len(ALTERNATE_COLORS)] if list.double: i *= 2 extra_row_height = 1 else: extra_row_height = 0 i += 1 grid_style.add("BACKGROUND", (0, i), (-1, i + extra_row_height), color) row = [] if list.account_width: row.append(a.name) # Check if we need to reduce col font size while ( col_width[len(row) - 1] < p.stringWidth(row[-1], font_name, font_size_name) + 12 and font_size_name > font_size_min ): font_size_name -= 1 if list.short_name_width: short_name = a.short_name if not short_name and a.owner: short_name = a.owner.username row.append(short_name or a.name) # Check if we need to reduce col font size while ( col_width[len(row) - 1] < p.stringWidth(row[-1], font_name, font_size_name) + 12 and font_size_short_name > font_size_min ): font_size_short_name -= 1 if list.balance_width: row.append("%d" % a.normal_balance()) # XXX: currently warnings are only shown if balance is shown, this # if needs to be moved if you want to change that if a.needs_warning(): grid_style.add( "FONTNAME", (0, i), (base_x - 1, i), font_name_bold ) grid_style.add( "TEXTCOLOR", (base_x - 1, i), (base_x - 1, i), WARN_TEXT_COLOR, ) # Check if we need to reduce col font size while ( col_width[len(row) - 1] < p.stringWidth(str(row[-1]), font_name, font_size_balance) + 12 and font_size_balance > font_size_min ): font_size_balance -= 1 if a.is_blocked(): if list.balance_width: grid_style.add( "TEXTCOLOR", (base_x - 1, i), (base_x - 1, i), BLACKLISTED_TEXT_COLOR, ) grid_style.add( "FONTNAME", (0, i), (base_x - 1, i), font_name_bold ) grid_style.add( "BACKGROUND", (base_x, i), (-1, i + extra_row_height), BLACKLISTED_COLOR, ) row.extend([""] * len(header[base_x:])) else: row.extend(header[base_x:]) data.append(row) if list.double: data.append([""] * len(row)) grid_style.add("SPAN", (0, i), (0, i + extra_row_height)) if list.balance_width: grid_style.add("SPAN", (1, i), (1, i + extra_row_height)) grid_style.add("FONTSIZE", (0, 0), (-1, -1), font_size_small) # Set font size for names grid_style.add("FONTSIZE", (0, 1), (0, -1), font_size_name) grid_style.add("ALIGN", (0, 0), (-1, -1), "LEFT") grid_style.add("ALIGN", (base_x, 0), (-1, -1), "RIGHT") grid_style.add("FONTNAME", (0, 0), (-1, 0), font_name_bold) # Set font size for balance if list.balance_width: grid_style.add( "FONTSIZE", (base_x - 1, 1), (base_x - 1, -1), font_size_balance ) grid_style.add("ALIGN", (base_x - 1, 1), (base_x - 1, -1), "RIGHT") grid_style.add("TEXTCOLOR", (base_x, 1), (-1, -1), FAINT_COLOR) if list.double: grid_style.add("TOPPADDING", (base_x, 1), (-1, -1), 2) grid_style.add("BOTTOMPADDING", (base_x, 1), (-1, -1), 2) grid_style.add("VALIGN", (0, 1), (-1, -1), "TOP") grid_style.add("GRID", (0, 0), (-1, -1), 0.25, BORDER_COLOR) # Create table t = Table(data, colWidths=col_width, style=grid_style, repeatRows=1) rest = None avail_w = width - 2 * margin avail_h = height - 2 * margin - head_height - foot_height while t: # Figure out how big table will be t_width, t_height = t.wrapOn(p, avail_w, avail_h) if not rest and t_height > height - 2 * margin - head_height: t, rest = t.split(avail_w, avail_h) continue # Draw on canvas draw_header() t.drawOn(p, margin, height - t_height - margin - head_height) draw_footer() if rest: # set t to the second table and reset rest t, rest = (rest, None) # Show new page p.showPage() else: # Leave loop break p.save() return content
def generate_pdf(pdfname, InvoiceNo, create_date, carrier, address, totalfee, tc, payment): #设置页面大小 c = canvas.Canvas(pdfname + '.pdf', pagesize=A4) xlength, ylength = A4 print('width:%d high:%d' % (xlength, ylength)) #c.line(1,1,ylength/2,ylength) #设置文字类型及字号 c.setFont('Helvetica', 12) #简单的图片载入 imageValue = 'test.jpg' #c.drawImage(imageValue,97,97,300,300) c.drawImage('test.jpg', 50, 750, 200, 50) #text gengerating def set_text(x, y, text1): indexVlaue = 0 set_text = c.beginText(x, y) while (indexVlaue < ylength): textStr = text1 #print('nextline,nextline%d'%indexVlaue) set_text.textLine(textStr) indexVlaue = indexVlaue + 1 break c.drawText(set_text) #tc = [['ELD Subscription & Data Plan','12/01/2018-12/01/2019 (12 month)','3','$1197','0']] atable = tc set_text(50, ylength - 110, "Invoice#: " + InvoiceNo) set_text(400, ylength - 110, "Created: " + create_date) set_text(50, ylength - 150, "Supplier: United Bus Technology Inc.") set_text(50, ylength - 165, "Address: 7926 Jones Branch Dr. Suite 630, McLean, VA 22102") set_text(50, ylength - 190, "Motor Carrier:" + carrier) set_text(50, ylength - 205, "Address:" + address) set_text(400, 280, "Total Fee: $" + totalfee) set_text(50, 250, "Thanks for purchase!") set_text(50, 235, "For any further questions do not hesitate to contact us!") set_text(50, 200, "Website: https://www.ubtshield.com/") set_text(50, 185, "Address: 7926 Jones Branch Dr., Suite 630, VA 22102") set_text(50, 170, "Phone: +1 202 800 6565") set_text(50, 155, "Email: [email protected]") if payment == "Paid": c.drawImage('paid.jpg', 400, 200, 120, 120) elif payment == "Not Paid": c.drawImage('notpaid.jpg', 400, 200, 120, 120) t = Table(atable, colWidths=[150, 170, 40, 60, 60]) t.setStyle( TableStyle([ ('ALIGN', (0, 0), (4, len(atable) - 1), 'CENTER'), ('INNERGRID', (0, 0), (-1, -1), 0.25, colors.black), ('BOX', (0, 0), (-1, -1), 0.25, colors.black), ])) t.split(0, 0) t.drawOn(c, 50, ylength - 400, 1) c.showPage() #换页的方式不同的showPage c.drawString(0,0,'helloword') c.save()
def pdf(group, list, show_header=True, show_footer=True): """PDF version of list""" content = StringIO() columns = list.column_set.all() accounts = list.accounts() margin = 0.5*cm font_name = 'Times-Roman' font_name_bold = 'Times-Bold' font_size = 12 font_size_small = 10 font_size_min = 8 head_height = 30 # pt foot_height = 15 # pt logo_height = 25 # pt font_size_name = font_size_small font_size_short_name = font_size_small font_size_balance = font_size_small if list.orientation == list.LANDSCAPE: height, width = A4 else: width, height = A4 # Create canvas for page and set fonts p = canvas.Canvas(content, (width, height)) show_logo = bool(group.logo and group.logo.storage.exists(group.logo.path)) if show_logo: # Find scaling ratio ratio = group.logo.width / group.logo.height # Load logo with correct scaling logo = Image( group.logo.path, width=logo_height*ratio, height=logo_height) def draw_header(): if not show_header: return if show_logo: logo.drawOn( p, width - margin - logo_height*ratio, height - margin - logo_height) # Setup rest of header p.setFont(font_name, font_size) p.drawString( margin, height - margin - font_size, u'%s: %s' % (group, list.name)) p.setFont(font_name, font_size_small) p.drawString( margin, height - margin - font_size - font_size + 2, u'%s: %s' % (_('Printed'), str(date.today()))) footer = [] if group.email: footer.append(group.email) if group.account_number: footer.append(group.get_account_number_display()) if list.comment.strip(): footer.append(list.comment.replace('\n', ' ').replace('\r', ' ')) def draw_footer(): if not show_footer: return p.drawString(margin, margin, u' - '.join(footer)) blacklisted_note = _(u'Blacklisted accounts are marked with: ') p.drawRightString(width - margin - 10, margin, blacklisted_note) p.setFillColor(BLACKLISTED_COLOR) p.rect(width - margin - 10, margin, 8, 8, fill=1, stroke=0) p.setFont(font_name, font_size) if not accounts: no_accounts_message = _(u"Sorry, this list is empty.") draw_header() p.drawString( margin, height - font_size - margin - head_height, no_accounts_message) draw_footer() p.save() return content elif not columns: no_columns_message = _( u"Sorry, this list isn't set up correctly, " u"please add some columns.") draw_header() p.drawString( margin, height - font_size - margin - head_height, no_columns_message) draw_footer() p.save() return content # Store col widths col_width = [] header = [_(u'Name')] if list.account_width: col_width.append(list.account_width) if list.short_name_width: col_width.append(list.short_name_width) if list.account_width and list.short_name_width: header.append('') if list.balance_width: header.append(_(u'Balance')) col_width.append(list.balance_width) if list.short_name_width > 0 and list.account_width > 0: GRID_STYLE.add('SPAN', (0, 0), (1, 0)) base_x = len(header) for c in columns: header.append(c.name) col_width.append(c.width) # Calculate relative col widths over to absolute points for i, w in enumerate(col_width): col_width[i] = float(w) / float( (list.listcolumn_width or 0) + list.balance_width + (list.account_width or 0) + (list.short_name_width or 0) ) * (width - 2 * margin) # Intialise table with header data = [header] for i, a in enumerate(accounts): color = ALTERNATE_COLORS[(i+1) % len(ALTERNATE_COLORS)] if list.double: i *= 2 extra_row_height = 1 else: extra_row_height = 0 i += 1 GRID_STYLE.add('BACKGROUND', (0, i), (-1, i+extra_row_height), color) row = [] if list.account_width: row.append(a.name) # Check if we need to reduce col font size while ( col_width[len(row)-1] < p.stringWidth(row[-1], font_name, font_size_name) + 12 and font_size_name > font_size_min): font_size_name -= 1 if list.short_name_width: short_name = a.short_name if not short_name and a.owner: short_name = a.owner.username row.append(short_name or a.name) # Check if we need to reduce col font size while ( col_width[len(row)-1] < p.stringWidth(row[-1], font_name, font_size_name) + 12 and font_size_short_name > font_size_min): font_size_short_name -= 1 if list.balance_width: row.append('%d' % a.normal_balance()) # XXX: currently warnings are only shown if balance is shown, this # if needs to be moved if you want to change that if a.needs_warning(): GRID_STYLE.add( 'FONTNAME', (0, i), (base_x - 1, i), font_name_bold) GRID_STYLE.add( 'TEXTCOLOR', (base_x - 1, i), (base_x - 1, i), WARN_TEXT_COLOR) # Check if we need to reduce col font size while ( col_width[len(row)-1] < p.stringWidth(str(row[-1]), font_name, font_size_balance) + 12 and font_size_balance > font_size_min): font_size_balance -= 1 if a.is_blocked(): if list.balance_width: GRID_STYLE.add( 'TEXTCOLOR', (base_x - 1, i), (base_x - 1, i), BLACKLISTED_TEXT_COLOR) GRID_STYLE.add( 'FONTNAME', (0, i), (base_x - 1, i), font_name_bold) GRID_STYLE.add( 'BACKGROUND', (base_x, i), (-1, i + extra_row_height), BLACKLISTED_COLOR) row.extend([''] * len(header[base_x:])) else: row.extend(header[base_x:]) data.append(row) if list.double: data.append([''] * len(row)) GRID_STYLE.add('SPAN', (0, i), (0, i + extra_row_height)) if list.balance_width: GRID_STYLE.add('SPAN', (1, i), (1, i + extra_row_height)) GRID_STYLE.add('FONTSIZE', (0, 0), (-1, -1), font_size_small) # Set font size for names GRID_STYLE.add('FONTSIZE', (0, 1), (0, -1), font_size_name) GRID_STYLE.add('ALIGN', (0, 0), (-1, -1), 'LEFT') GRID_STYLE.add('ALIGN', (base_x, 0), (-1, -1), 'RIGHT') GRID_STYLE.add('FONTNAME', (0, 0), (-1, 0), font_name_bold) # Set font size for balance if list.balance_width: GRID_STYLE.add( 'FONTSIZE', (base_x - 1, 1), (base_x - 1, -1), font_size_balance) GRID_STYLE.add('ALIGN', (base_x - 1, 1), (base_x - 1, -1), 'RIGHT') GRID_STYLE.add('TEXTCOLOR', (base_x, 1), (-1, -1), FAINT_COLOR) if list.double: GRID_STYLE.add('TOPPADDING', (base_x, 1), (-1, -1), 2) GRID_STYLE.add('BOTTOMPADDING', (base_x, 1), (-1, -1), 2) GRID_STYLE.add('VALIGN', (0, 1), (-1, -1), 'TOP') GRID_STYLE.add('GRID', (0, 0), (-1, -1), 0.25, BORDER_COLOR) # Create table t = Table(data, colWidths=col_width, style=GRID_STYLE, repeatRows=1) rest = None avail_w = width-2*margin avail_h = height - 2*margin - head_height - foot_height while t: # Figure out how big table will be t_width, t_height = t.wrapOn(p, avail_w, avail_h) if not rest and t_height > height - 2*margin - head_height: t, rest = t.split(avail_w, avail_h) continue # Draw on canvas draw_header() t.drawOn(p, margin, height - t_height - margin - head_height) draw_footer() if rest: # set t to the second table and reset rest t, rest = (rest, None) # Show new page p.showPage() else: # Leave loop break p.save() return content
class DelayedTable(Table): """A flowable that inserts a table for which it has the data. Needed so column widths can be determined after we know on what frame the table will be inserted, thus making the overal table width correct. """ def __init__(self, data, colWidths, style=None, repeatrows=False, splitByRow=True): self.data = data self._colWidths = colWidths if style is None: style = TableStyle( [ ('LEFTPADDING', (0, 0), (-1, -1), 0), ('RIGHTPADDING', (0, 0), (-1, -1), 0), ('TOPPADDING', (0, 0), (-1, -1), 0), ('BOTTOMPADDING', (0, 0), (-1, -1), 0), ] ) self.style = style self.t = None self.repeatrows = repeatrows self.hAlign = TA_CENTER self.splitByRow = splitByRow def wrap(self, w, h): # Create the table, with the widths from colWidths reinterpreted # if needed as percentages of frame/cell/whatever width w is. # _tw = w/sum(self.colWidths) def adjust(*args, **kwargs): kwargs['total'] = w return styles.adjustUnits(*args, **kwargs) # adjust=functools.partial(styles.adjustUnits, total=w) self.colWidths = [adjust(x) for x in self._colWidths] # colWidths = [_w * _tw for _w in self.colWidths] self.t = Table( self.data, colWidths=self.colWidths, style=self.style, repeatRows=self.repeatrows, splitByRow=True, ) self._set_max_page_height_on_cell_flowables(h) # splitByRow=self.splitByRow) self.t.hAlign = self.hAlign return self.t.wrap(w, h) def _set_max_page_height_on_cell_flowables(self, height): """Iterate over all cells in the table and set the maximum height onto the flowable. This is useful to the flowable if its data cannot be rendered over a page boundary (e.g. an image) as it can then resize itself to a valid height in its wrap() method. """ def set_max_page_height_on_flowable(flowable, cell_style): if hasattr(flowable, 'max_page_height'): # Subtract padding from h only if it is a positive value top_padding = cell_style.topPadding if cell_style.topPadding > 0 else 0 bottom_padding = ( cell_style.topPadding if cell_style.bottomPadding > 0 else 0 ) h = abs(height - top_padding - bottom_padding) - _FUZZ flowable.max_page_height = h for row_index, row in enumerate(self.data): for col_index, columns in enumerate(row): # columns is either a list or a cell (for a single cell table) if isinstance(columns, list): for cell in columns: set_max_page_height_on_flowable( cell, self.t._cellStyles[row_index][col_index] ) else: set_max_page_height_on_flowable( columns, self.t._cellStyles[row_index][col_index] ) def split(self, w, h): if self.splitByRow: if not self.t: self.wrap(w, h) return self.t.split(w, h) else: return [] def drawOn(self, canvas, x, y, _sW=0): self.t.drawOn(canvas, x, y, _sW) def identity(self, maxLen=None): return "<%s at %s%s%s> containing: %s" % ( self.__class__.__name__, hex(id(self)), self._frameName(), getattr(self, 'name', '') and (' name="%s"' % getattr(self, 'name', '')) or '', repr(self.data[0]), )[:180]