class Report(object): """ PDF report for plots generated on the basis of raw eye-tracking data. """ def __init__(self, file_handler, report_file_name, open_after_download_flag, properties): self.file_handler = file_handler self.open_after_download = open_after_download_flag self.properties = properties self.font_path = join(self.file_handler.fonts_dir, 'DejaVuSans.ttf') # unicode font self.pdf = FPDF(orientation='P', unit='mm', format='A4') fpdf.set_global("FPDF_CACHE_MODE", 1) # get date & time current_date = datetime.now().strftime("%d.%m.%Y %H:%M") current_timestamp = str(time.time()).replace('.', '') self.title = properties.report_title self.subtitle = properties.report_subtitle self.subtitle_date = properties.subtitle_with_date.format(current_date) self.subtitle_rec_dir = properties.subtitle_with_rec_dir_path.format( self.file_handler.recording_dir) self.subtitle_export_dir = properties.subtitle_with_exported_dir_path.format( self.file_handler.exports_dir) self.pdf_file_name = properties.pdf_report_file_name.format( current_timestamp ) if report_file_name == "" else report_file_name + ".pdf" # table with fixation_report.csv data self.fixation_detector_table_description = properties.fixation_detector_table_description self.parameter_table_header_name = properties.fixation_detector_settings_values_param self.value_table_header_name = properties.fixation_detector_settings_values_val self.target_file_path = join(self.file_handler.downloads_dir, self.pdf_file_name) self.title_font_size = 25 self.subtitle_font_size = 20 self.subsection_title_fontsize = 25 self.paragraph_fontsize = 14 def add_first_page(self): """ Creates report first page with: title, date, # recording_directory # and exports_directory """ title_line_break_value = 90 self.pdf.add_page() # add first report page self.pdf.ln(title_line_break_value) self.pdf.alias_nb_pages() # Create the special value {nb} self.pdf.set_margins(left=10.00, top=10.00, right=10.00) self.pdf.set_font("Courier", 'B', size=self.title_font_size) self.pdf.cell(w=190, h=15, txt=self.title, ln=1, align="C") self.pdf.set_font("Courier", 'B', size=self.subtitle_font_size) self.pdf.cell(w=190, h=10, txt=self.subtitle, ln=1, align="C") self.pdf.set_font("Arial", size=10) self.pdf.cell(w=190, h=10, txt=self.subtitle_date, ln=1, align="C") left = self.pdf.l_margin right = self.pdf.r_margin top = self.pdf.t_margin bottom = self.pdf.b_margin # Effective page width and height epw = self.pdf.w - left - right eph = self.pdf.h - top - bottom self.pdf.rect(left, top, w=epw, h=eph) # draw margins def add_subsection(self, title, description): self.pdf.add_page() self.pdf.set_font("Courier", 'B', size=self.subsection_title_fontsize) self.pdf.cell(w=190, h=15, txt=title, ln=1, align="L") self.add_unicode_font(14) self.pdf.multi_cell(w=190, h=10, txt=self.pdf.normalize_text(description)) def add_fixation_report(self, fixation_report_obj): self.add_unicode_font(14) epw = self.pdf.w - 2 * self.pdf.l_margin # effective page width, or just epw col_width = epw / 2 # distribute columns content evenly across table and page data = { self.parameter_table_header_name: self.value_table_header_name, "max_dispersion": fixation_report_obj.max_dispersion, "min_duration": fixation_report_obj.min_duration, "max_duration": fixation_report_obj.max_duration, "fixation_count": fixation_report_obj.fixation_count } th = self.pdf.font_size self.pdf.multi_cell(w=190, h=8, txt=self.fixation_detector_table_description, align="L") counter = 0 for key, value in data.items(): counter += 1 if counter == 1: self.pdf.cell(w=col_width, h=(2 * th), txt=self.pdf.normalize_text(str(key)), border=1, align="C") self.pdf.cell(w=col_width, h=(2 * th), txt=self.pdf.normalize_text(str(value)), border=1, align="C") self.pdf.set_font(family="font", size=10) else: self.pdf.cell(col_width, 2 * th, self.pdf.normalize_text(str(key)), border=1, align="C") self.pdf.cell(col_width, 2 * th, self.pdf.normalize_text(str(value)), border=1, align="C") self.pdf.ln(2 * th) def add_plot(self, plot): self.pdf.add_page() try: self.pdf.image(plot.image_path, w=190) except FileNotFoundError as exception: logger.error(f"NOT FOUND file {plot.image_path}") print(exception) self.add_unicode_font(plot.fontsize) self.pdf.multi_cell(w=190, h=10, txt=self.pdf.normalize_text(plot.description)) def save_report(self): """ Saves report in /exports/../downloads directory """ logger.info(f'Save report into {self.target_file_path}') self.pdf.output(self.target_file_path) logger.info(f"Report '{self.pdf_file_name}' saved") logger.info(f"Report directory: {self.file_handler.downloads_dir}") if self.open_after_download: try: startfile(self.target_file_path) except: system("xdg-open \"%s\"" % self.target_file_path) def add_unicode_font(self, fontsize): print("FONT PATH: \n", self.font_path) self.pdf.add_font(family="font", fname=self.font_path, uni=True) self.pdf.set_font(family="font", size=fontsize)
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)