코딩 수업/파이썬 (업무자동화)

[업무자동화][용량다운] 학생 성적 Monthly Report 만드는 파이썬 프로그램 (화질은 유지하면서 용량 줄이기, Python Program for Creating Student Monthly Reports, 성적표, 리포트 만들기, 학생 성적 관리, 피드백)

Jade S. 2025. 3. 3. 12:03
728x90
반응형

>> pdf 1장인데 4M라 좀 큼. 1M 정도로 줄이기

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

# 파일 경로 설정
template_path = "C:/Users/MJ/Desktop/월간리포트만들기/template.png"  # 템플릿 이미지
grade_graph_path = "C:/Users/MJ/Desktop/월간리포트만들기/hg.png"  # 성적 그래프
progress_graph_path = "C:/Users/MJ/Desktop/월간리포트만들기/hp.png"  # 진도 그래프
font_path = "C:/Users/MJ/Desktop/월간리포트만들기/NanumGothic.ttf"  # 한글 폰트
excel_path = "C:/Users/MJ/Desktop/월간리포트만들기/StudentName.xlsx"  # 엑셀 파일 경로

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

# 'fg.png'에서 'f' 추출 (student_id)
student_id = grade_graph_path.split('/')[-1][0]  # 'f' 추출
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"C:/Users/MJ/Desktop/월간리포트만들기/MonthlyReport_{student_name}_{current_month}월.pdf"
temp_pdf_path = f"C:/Users/MJ/Desktop/월간리포트만들기/temp_MonthlyReport_{student_name}_{current_month}월.pdf"

# PDF로 저장 (용량 줄이기 위해 quality와 resolution 조정)
template = template.convert("RGB")  # JPEG는 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}")

>> 결과물

 

>> 결론

Hope it's the last revision...

728x90
반응형