본문 바로가기
코딩 수업/파이썬 (업무자동화)

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

by Jade S. 2025. 3. 3.
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
반응형