import os import pandas as pd from reportlab.pdfgen import canvas from reportlab.lib.pagesizes import letter import tempfile import matplotlib.pyplot as plt from reportlab.lib import colors from Damage_calculation import DamageCalculator from reportlab.platypus import Table, TableStyle class PDFReportGenerator: def __init__(self, output_csv, output_folder, pdf_path): self.output_csv = output_csv self.damage_folder = os.path.join(output_folder, 'damage/labels') self.parts_folder = os.path.join(output_folder, 'parts/labels') self.pdf_path = pdf_path self.calculator = DamageCalculator() def create_pie_chart(self, part_class, damage_summary): part_damage = damage_summary.get(part_class, {}) if not part_damage: return None damage_labels = list(part_damage['damage_types'].keys()) + ['Undamaged'] damage_values = list(part_damage['damage_types'].values()) + [part_damage['undamaged']] fig, ax = plt.subplots(figsize=(6, 6)) # Adjust the figure size to ensure the pie is circular ax.pie(damage_values, labels=damage_labels, autopct='%1.1f%%', startangle=140, textprops={'fontsize': 14}) # Increase font size ax.axis('equal') img_temp_path = tempfile.mktemp(suffix=".png") plt.savefig(img_temp_path, bbox_inches='tight') # Ensure the pie chart is properly sized plt.close(fig) return img_temp_path def add_table_to_pdf(self, pdf, dataframe, x_position, y_position): # Replace NaN values with '-' dataframe = dataframe.fillna('-') data = [dataframe.columns.to_list()] + dataframe.values.tolist() table = Table(data) # Define table style style = TableStyle([ ('BACKGROUND', (0, 0), (-1, 0), colors.grey), ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke), ('ALIGN', (0, 0), (-1, -1), 'CENTER'), ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'), ('FONTSIZE', (0, 0), (-1, 0), 12), ('BOTTOMPADDING', (0, 0), (-1, 0), 12), ('BACKGROUND', (0, 1), (-1, -1), colors.beige), ('GRID', (0, 0), (-1, -1), 1, colors.black) ]) table.setStyle(style) # Convert the table to a PDF flowable and draw it on the canvas table.wrapOn(pdf, x_position, y_position) table.drawOn(pdf, x_position, y_position) def generate_report(self): df = pd.read_csv(self.output_csv) car_parts = df['Car Parts'].unique() # Initialize damage summary dictionary damage_summary = {} # Populate damage and parts file paths damage_files = sorted(os.listdir(self.damage_folder)) parts_files = sorted(os.listdir(self.parts_folder)) # Iterate over the damage and parts files for damage_file, parts_file in zip(damage_files, parts_files): damage_path = os.path.join(self.damage_folder, damage_file) parts_path = os.path.join(self.parts_folder, parts_file) damage_classes, damage_polygons = self.calculator.parse_coordinates(damage_path) part_classes, part_polygons = self.calculator.parse_coordinates(parts_path) damage_polygons = list(zip(damage_classes, damage_polygons)) part_polygons = list(zip(part_classes, part_polygons)) part_summary = self.calculator.summarize_damage_by_part(damage_polygons, part_polygons) for part, summary in part_summary.items(): if part not in damage_summary: damage_summary[part] = summary else: for damage_type, percentage in summary['damage_types'].items(): if damage_type not in damage_summary[part]['damage_types']: damage_summary[part]['damage_types'][damage_type] = 0 damage_summary[part]['damage_types'][damage_type] += percentage damage_summary[part]['undamaged'] += summary['undamaged'] pdf = canvas.Canvas(self.pdf_path, pagesize=letter) pdf.setTitle("Car Damage Estimation Report") width, height = letter y_position = height - 40 for part_class in car_parts: if part_class == 'Total': continue pdf.setFont("Helvetica-Bold", 12) pdf.drawString(30, y_position, f'Damage Report for {part_class}') y_position -= 20 pie_chart_path = self.create_pie_chart(part_class, damage_summary) if pie_chart_path: pdf.drawImage(pie_chart_path, 50, y_position - 300, width=275, height=275) # Adjust size to maintain aspect ratio y_position -= 320 # Clean up the temporary file os.remove(pie_chart_path) if y_position < 100: pdf.showPage() y_position = height - 40 # Add title above the table y_position -= 40 pdf.setFont("Helvetica-Bold", 14) pdf.drawString(50, y_position, "Cost Breakdown Table") y_position -= 200 # Add table from CSV to the PDF self.add_table_to_pdf(pdf, df, 30, y_position-100) pdf.save()