본문 바로가기
코딩 수업/포트폴리오

[업무자동화][파이썬] 학생별 월간 리포트 자동 생성 파이썬 프로그램 (Python Program for Automating Monthly Reports for Students)

by Jade S. 2025. 3. 6.
728x90
반응형

프로젝트 설명:

이 파이썬 프로그램은 학생들의 월간 리포트를 자동으로 생성하는 프로그램입니다. 학생별 데이터를 결합하고 시각적 요소를 포함하여 형식화된 PDF 리포트를 생성함으로써 리포트 작성을 더 빠르고 효율적으로 만듭니다.

주요 기능:

  1. 학생 데이터 추출:
    • 엑셀 파일에서 학생 이름과 ID를 읽어옵니다.
    • 성적 그래프 이미지의 파일명에서 ID를 추출하여 해당 학생의 이름을 엑셀에서 검색하여 가져옵니다.
  2. 텍스트 및 그래픽 삽입:
    • 미리 디자인된 템플릿 이미지에 성적 그래프와 진도 그래프를 지정된 위치에 삽입합니다.
    • 피드백 텍스트의 글꼴 크기와 줄 간격을 조정하여 템플릿 내 지정된 박스에 맞게 자동으로 삽입합니다.
  3. PDF 생성:
    • 수정된 템플릿과 삽입된 그래프들을 하나의 문서로 결합합니다.
    • 출력 파일을 PDF 형식으로 저장하며, 크기와 해상도를 최적화하여 저장합니다.
    • PDF 압축을 통해 파일 크기를 줄입니다.
  4. 파일 처리:
    • 이미지, 폰트, 출력 PDF의 파일 경로를 자동으로 처리합니다.
    • PDF 생성 후 임시 파일을 삭제하여 시스템 자원을 효율적으로 관리합니다.

사용 사례:

이 프로그램은 학생들에게 개인화된 리포트를 생성해야 하는 교육자에게 유용합니다. 리포트 준비에 드는 시간을 절감하고, 일관된 피드백과 시각적 데이터를 포함시켜 전문적인 PDF 리포트를 자동으로 생성할 수 있습니다.

 

from PIL import Image, ImageDraw, ImageFont
import pandas as pd
from datetime import datetime
import fitz  # PyMuPDF
import os

# 파일 경로 설정
template_path = "템플릿 이미지 경로" 
grade_graph_path = "성적 그래프 경로"
progress_graph_path = "진도 그래프 경로"
font_path = "한글 폰트 경로"
excel_path = "엑셀 파일 경로" 

# 엑셀 파일에서 학생 이름 찾기
try:
    df = pd.read_excel(excel_path)
    print("엑셀 파일 로드 완료:")
    print(df)  # 엑셀 파일 내용 확인
except Exception as e:
    print(f"엑셀 파일 로드 실패: {e}")
    exit()

# 진도그래프 파일명에서 아이디추출 (student_id)
student_id = grade_graph_path.split('/')[-1][0]  # 아이디 추출
print(f"추출된 student_id: {student_id}")  # 디버깅 메시지

# student_id와 엑셀 파일의 id 열 데이터 타입 일치시키기
df['id'] = df['id'].astype(str).str.strip()  # id 열을 문자열로 변환하고 공백 제거
student_id = str(student_id).strip()  # student_id도 문자열로 변환하고 공백 제거

# 학생 이름 찾기
try:
    student_name = df.loc[df['id'] == student_id, 'student_name'].values[0]
    print(f"찾은 student_name: {student_name}")  # 디버깅 메시지
except IndexError:
    print(f"⚠️ 오류: student_id '{student_id}'에 해당하는 학생 이름을 찾을 수 없습니다.")
    exit()

# 템플릿 및 그래프 이미지 로드
template = Image.open(template_path)
grade_graph = Image.open(grade_graph_path)
progress_graph = Image.open(progress_graph_path)

# 텍스트 피드백 준비 (수동 입력)
feedback_text = """포토샵 CC (Creative Cloud)**는 어도비에서 제공하는 대표적인 이미지 편집 프로그램으로, 그래픽 디자인, 사진 편집, 디지털 아트, 웹 디자인 등 다양한 작업을 할 수 있는 소프트웨어입니다. CC는 "Creative Cloud"의 약자로, 클라우드 기반 서비스로, 인터넷을 통해 최신 버전 업데이트, 파일 공유, 동기화 등이 가능합니다.

포토샵 CC는 레이어 기반 편집, 고급 필터와 효과 적용, 벡터 작업, 타이포그래피 작업 등 다양한 기능을 제공하여 전문가뿐만 아니라 취미로 사용하는 사람들에게도 유용합니다. 스마트 오브젝트, 고급 색상 조정, 3D 모델링 등의 기능도 지원하고 있어, 창의적인 작업을 위한 강력한 도구입니다.
"""
text_box_x = 226
text_box_y = 5334
text_box_width = 4156  # 텍스트 박스 폭
text_box_height = 1021  # 텍스트 박스 높이

# 폰트 크기 및 줄 간격 설정
font_size = 100
min_font_size = 50
max_font_size = 120
line_spacing = 20
max_iterations = 100  # 무한 루프 방지
iteration = 0

# 텍스트 크기 조정 루프
while iteration < max_iterations:
    iteration += 1  # 반복 횟수 증가

    font = ImageFont.truetype(font_path, font_size)
    wrapped_text = []
    current_line = ""

    for word in feedback_text.split():
        test_line = f"{current_line} {word}".strip()
        bbox = font.getbbox(test_line)
        text_width = bbox[2] - bbox[0]

        if text_width <= text_box_width:
            current_line = test_line
        else:
            wrapped_text.append(current_line)
            current_line = word

    wrapped_text.append(current_line)

    # 전체 텍스트 높이 계산
    total_height = sum(font.getbbox(line)[3] - font.getbbox(line)[1] + line_spacing for line in wrapped_text) - line_spacing

    # 텍스트 크기 조정
    if total_height > text_box_height:  
        font_size -= 2
        line_spacing = max(10, line_spacing - 1)
    elif total_height < text_box_height * 0.9:
        font_size += 2
        line_spacing += 1
    else:
        break  # 박스에 적절히 맞으면 종료

    # 최소 글자 크기 제한
    if font_size < min_font_size:
        print("⚠️ 글자 크기가 너무 작아졌습니다. 텍스트 크기 조정을 중단합니다.")
        font_size = min_font_size
        break

    # 디버깅 메시지 출력
    print(f"Iteration {iteration}: Font Size = {font_size}, Line Spacing = {line_spacing}")

# 루프 종료 확인
if iteration == max_iterations:
    print("🚨 경고: 최대 반복 횟수를 초과하여 루프를 종료합니다.")

print("✅ 최종 텍스트 배치 완료")

# 텍스트 삽입
draw = ImageDraw.Draw(template)
y_position = text_box_y
for line in wrapped_text:
    draw.text((text_box_x, y_position), line, font=font, fill="black")
    y_position += font.getbbox(line)[3] - font.getbbox(line)[1] + line_spacing

# 그래프 크기 및 위치 설정
grade_graph = grade_graph.resize((4234, 2142))
progress_graph = progress_graph.resize((4270, 1356))

template.paste(grade_graph, (196, 992))
template.paste(progress_graph, (178, 3511))

# PDF 저장 경로 생성
current_month = datetime.now().month
pdf_path = f"PDF 저장경로/MonthlyReport_{student_name}_{current_month}월.pdf"
temp_pdf_path = f"임시파일 저장경로/temp_MonthlyReport_{student_name}_{current_month}월.pdf"

# PDF로 저장
template = template.convert("RGB")
template.save(temp_pdf_path, "PDF", resolution=200.0, quality=70, optimize=True)

# PDF 압축
doc = fitz.open(temp_pdf_path)
doc.save(pdf_path, garbage=4, deflate=True, clean=True)
doc.close()

# 임시 파일 삭제
os.remove(temp_pdf_path)

print(f"🎉 성적표 PDF가 성공적으로 생성되었습니다: {pdf_path}")

 

결과물:

728x90
반응형