#!/usr/bin/env python3 import argparse import math import operator import fpdf import strictyaml class Chart: def __init__(self): self.parser = self.get_parser() self.args = self.parser.parse_args() self.data = strictyaml.load(self.args.chart_data.read()).data def get_parser(self): parser = argparse.ArgumentParser() parser.add_argument( "chart_data", type=argparse.FileType("r") ) parser.add_argument( "--output", type=argparse.FileType("w"), default=None, help="Destination file", ) parser.add_argument( "--columns", "-c", default=4, type=int, help="Number of columns per page", ) parser.add_argument( "--rows", "-r", default=16, type=int, help="Number of rows per page", ) parser.add_argument( "--index-columns", "-i", default=6, type=int, help="Number of columns per index page", ) parser.add_argument( "--background-fill", "-b", action=argparse.BooleanOptionalAction, default=True, help="Fill the background with the target colour", ) return parser def get_arranged_cells(self): per_page = self.args.columns * self.args.rows padded = self.data["colours"] + [{}] * ( per_page - len(self.data["colours"]) % per_page ) pages = [ padded[i * per_page:i * per_page + per_page] for i in range(len(padded) // per_page) ] cells = [ [ [p[i + self.args.rows * j] for j in range(self.args.columns)] for i in range(len(p) // self.args.columns) ] for p in pages ] return(cells) def get_index(self): index = [ (c["label"], i // self.args.rows) for i, c in enumerate(self.data["colours"]) ] index.sort(key=operator.itemgetter(0)) return index def write_pdf(self): pdf = fpdf.FPDF(format="A5") pdf.add_font( family="FreeSans", fname="/usr/share/fonts/opentype/freefont/FreeSans.otf", ) pdf.add_font( family="FreeSans", style="B", fname="/usr/share/fonts/opentype/freefont/FreeSansBold.otf", ) pdf.add_font( family="FreeSerif", fname="/usr/share/fonts/opentype/freefont/FreeSerif.otf", ) for p_num, page in enumerate(self.get_arranged_cells()): pdf.add_page() pdf.set_font("FreeSerif", size=10) cell_width = (148 - 20) / (self.args.columns * 2) pdf.cell(64, 8, self.data["title"], align="C") pdf.ln() pdf.set_font("FreeSans", "B", 10) for j in range(self.args.columns): pdf.cell(cell_width, 8, str(j + p_num * self.args.columns),) pdf.cell(cell_width, 8, "") pdf.ln() for row in page: for cell in row: if cell: pdf.set_fill_color(255,255,255) if self.args.background_fill and cell.get("bg"): pdf.set_fill_color(*map(int, cell["bg"].split())) pdf.cell(cell_width, 8, "", border=1, fill=True) pdf.cell(cell_width, 8, cell["label"], ) pdf.ln(10) pdf.add_page() pdf.set_font("FreeSerif", size=10) cell_width = (148 - 20) / (self.args.columns * 2) pdf.cell(64, 8, self.data["title"], align="C") pdf.ln() pdf.set_font("FreeSerif", size=10) with pdf.text_columns( ncols=self.args.index_columns, balance=True, gutter=4, text_align="RIGHT", ) as cols: for c in self.get_index(): pdf.set_font("FreeSerif", size=10) cols.write(str(c[0])) cols.write(" ") pdf.set_font("FreeSans", "B", size=10) cols.write(str(c[1])) cols.ln() fname = ( getattr(self.args.output, "name", None) or self.args.chart_data.name.replace(".yaml", ".pdf") ) print(fname) pdf.output(fname) if __name__ == "__main__": Chart().write_pdf()