| | 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))
|
| | ax.pie(damage_values, labels=damage_labels, autopct='%1.1f%%', startangle=140, textprops={'fontsize': 14})
|
| | ax.axis('equal')
|
| |
|
| | img_temp_path = tempfile.mktemp(suffix=".png")
|
| | plt.savefig(img_temp_path, bbox_inches='tight')
|
| | plt.close(fig)
|
| | return img_temp_path
|
| |
|
| | def add_table_to_pdf(self, pdf, dataframe, x_position, y_position):
|
| |
|
| | dataframe = dataframe.fillna('-')
|
| |
|
| | data = [dataframe.columns.to_list()] + dataframe.values.tolist()
|
| | table = Table(data)
|
| |
|
| |
|
| | 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)
|
| |
|
| |
|
| | 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()
|
| |
|
| |
|
| | damage_summary = {}
|
| |
|
| |
|
| | damage_files = sorted(os.listdir(self.damage_folder))
|
| | parts_files = sorted(os.listdir(self.parts_folder))
|
| |
|
| |
|
| | 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)
|
| | y_position -= 320
|
| |
|
| |
|
| | os.remove(pie_chart_path)
|
| |
|
| | if y_position < 100:
|
| | pdf.showPage()
|
| | y_position = height - 40
|
| |
|
| |
|
| | y_position -= 40
|
| | pdf.setFont("Helvetica-Bold", 14)
|
| | pdf.drawString(50, y_position, "Cost Breakdown Table")
|
| | y_position -= 200
|
| |
|
| |
|
| | self.add_table_to_pdf(pdf, df, 30, y_position-100)
|
| |
|
| | pdf.save()
|
| |
|