AI with 재미

python 한글 문제 테스트

jhinux 2025. 11. 1. 21:25

matlib 에서 한글을 해결하기 위한 문제는 많으나.

WSL2 , Ubuntu  에서는 해결되지 않음 

 

이에 GPT 와 대화 끝에 생성된 코드 첨부 

 

# -*- coding: utf-8 -*-
"""
korean_font_wsl_test.py
WSL2(Ubuntu 22.04)에서 한글 깨짐 및 폰트 관련 이슈 점검/해결 올인원 스크립트

기능:
- 환경/인코딩 정보 출력
- 콘솔 출력 테스트
- UTF-8 파일 입출력 테스트
- Matplotlib: 안전 폰트 목록 적용(코딩 폰트 제외) + PNG/PDF 저장
- Pillow: 안전 폰트로 이미지 저장

폰트 우선순위(폴백 포함):
- NanumGothic → Noto Sans CJK KR → DejaVu Sans
- 'Coding' 이름의 폰트(예: NanumGothicCoding)는 제외

WSL 팁:
- WSL은 Windows 폰트를 자동 사용하지 않습니다.
- 반드시 WSL 내부에 폰트를 설치해야 합니다:
  sudo apt install -y fonts-nanum fonts-noto-cjk fonts-dejavu-core
"""

import sys
import os
import platform
import locale
from pathlib import Path
from typing import Optional, List

import matplotlib
import matplotlib.pyplot as plt
from matplotlib import font_manager as fm
from PIL import Image, ImageDraw, ImageFont
# ===== 사용자 설정 =====
OUTPUT_DIR = Path("korean_font_test_output")
OUTPUT_DIR.mkdir(exist_ok=True)

# 테스트 텍스트
RAW_TEST_TEXT = "안녕하세요, 파이썬! 한글 테스트 — 숫자: 123, 기호: ±−×"
# 안전 모드: 유니코드 마이너스(−, U+2212)를 ASCII 하이픈(-)으로 치환
USE_SAFE_MINUS = True
TEST_TEXT = RAW_TEST_TEXT.replace("−", "-") if USE_SAFE_MINUS else RAW_TEST_TEXT

# 출력 파일
TEXT_FILE = OUTPUT_DIR / "hello_korean.txt"
PNG_FILE = OUTPUT_DIR / "matplotlib_korean.png"
PDF_FILE = OUTPUT_DIR / "matplotlib_korean.pdf"
PIL_PNG_FILE = OUTPUT_DIR / "pil_korean.png"

# 안전 폰트 이름(정확 이름 매칭; 순서=우선순위)
SAFE_FONT_NAMES = [
    "NanumGothic",       # 일반 나눔고딕 (Coding 제외)
    "Noto Sans CJK KR",  # 한글/다국어 지원 넓음
    "DejaVu Sans",       # 기호/수학 글리프 보강
]

# 'Coding' 폰트는 제외 (예: NanumGothicCoding)
EXCLUDE_KEYWORDS = ["coding"]


# ===== 유틸 =====
def is_wsl() -> bool:
    rel = platform.release().lower()
    return "microsoft" in rel or "wsl" in rel


def print_env_info():
    print("=== 환경 정보 ===")
    print(f"Python: {platform.python_version()} ({sys.executable})")
    print(f"OS: {platform.system()} {platform.release()} ({platform.version()})")
    print(f"WSL 감지: {is_wsl()}")
    print(f"Matplotlib: {matplotlib.__version__}, Backend: {matplotlib.get_backend()}")
    print(f"sys.stdout.encoding: {sys.stdout.encoding}")
    try:
        pref = locale.getpreferredencoding(False)
    except Exception:
        pref = "N/A"
    print(f"locale.getpreferredencoding(False): {pref}")
    print(f"FileSystemEncoding: {sys.getfilesystemencoding()}")
    print("")


def try_fix_console_encoding():
    enc = (sys.stdout.encoding or "").upper()
    if "UTF-8" not in enc:
        try:
            sys.stdout.reconfigure(encoding="utf-8")  # Py3.7+
            print("[정보] sys.stdout 인코딩을 UTF-8로 재설정했습니다.")
        except Exception as e:
            print("[참고] 콘솔 인코딩 자동 재설정 실패:", repr(e))
            print(" - VS Code/터미널이 UTF-8인지 확인")
            print(" - PYTHONUTF8=1 환경변수 설정 권장\n")


def find_font_paths_by_exact_names(names: List[str]) -> List[str]:
    """정확한 폰트 이름 일치로 경로 수집, EXCLUDE_KEYWORDS 포함 시 제외"""
    matched = []
    for fe in fm.fontManager.ttflist:
        name = (fe.name or "")
        if any(k in name.lower() for k in EXCLUDE_KEYWORDS):
            continue
        if name in names and fe.fname and os.path.exists(fe.fname):
            matched.append(fe.fname)
    return matched


def setup_matplotlib_fonts_safe():
    """Matplotlib에 안전 폰트 목록 적용 + 폴백"""
    # 축 라벨의 마이너스는 ASCII '-'로 강제 (tick 라벨 안전)
    plt.rcParams["axes.unicode_minus"] = False

    # (선택) PDF에서 14 core fonts 고정 사용 해제
    plt.rcParams["pdf.use14corefonts"] = False

    font_paths = find_font_paths_by_exact_names(SAFE_FONT_NAMES)

    families = []
    for path in font_paths:
        fm.fontManager.addfont(path)
        fam = fm.FontProperties(fname=path).get_name()
        families.append(fam)

    if families:
        plt.rcParams["font.family"] = families  # 리스트 설정 → 글리프 폴백 유도
        print(f"[Matplotlib] 적용 폰트 목록: {families}")
    else:
        print("[경고] 안전 폰트를 찾지 못했습니다. 시스템 기본 폰트를 사용합니다.")
        print(" - 설치 확인: sudo apt install -y fonts-nanum fonts-noto-cjk fonts-dejavu-core")
        print(" - 캐시 초기화: rm -rf ~/.cache/matplotlib/*")


def test_console_output():
    print("=== 콘솔 출력 테스트 ===")
    print(TEST_TEXT)
    print("-> 위 텍스트가 콘솔에 정상적으로 한글로 보이나요?\n")


def test_file_io():
    print("=== 파일 입출력 테스트 (UTF-8) ===")
    with open(TEXT_FILE, "w", encoding="utf-8") as f:
        f.write(TEST_TEXT + "\n")
    print(f"쓰기 완료: {TEXT_FILE}")

    with open(TEXT_FILE, "r", encoding="utf-8") as f:
        content = f.read().strip()
    print("읽은 내용:", content)
    print("-> 파일에 한글이 깨지지 않고 저장/읽기 되는지 확인하세요.\n")


def test_matplotlib_output():
    print("=== Matplotlib 출력 테스트 ===")
    fig, ax = plt.subplots(figsize=(8, 4), dpi=150)
    ax.set_title("한글 폰트 테스트 (Matplotlib)")
    ax.plot([1, 2, 3], [3, 1, 4], marker="o", label="데이터")
    ax.legend()
    ax.set_xlabel("가로축")
    ax.set_ylabel("세로축")
    ax.text(0.05, 0.80, TEST_TEXT, transform=ax.transAxes)

    # RAW 텍스트 비교(옵션): 유니코드 마이너스를 그대로 넣어보는 라인
    ax.text(0.05, 0.68, f"(RAW) {RAW_TEST_TEXT}", fontsize=9, color="dimgray",
            transform=ax.transAxes)

    fig.tight_layout()
    fig.savefig(PNG_FILE)
    fig.savefig(PDF_FILE)
    plt.close(fig)
    print(f"저장 완료: {PNG_FILE}, {PDF_FILE}")
    print("-> 이미지/PDF에서 한글과 기호가 정상인지 확인하세요.\n")


def _choose_pillow_font_path() -> Optional[str]:
    """Pillow에서 사용할 트루타입 폰트 경로 선택 (안전 목록 우선)"""
    # Matplotlib에서 찾은 경로 재사용
    paths = find_font_paths_by_exact_names(SAFE_FONT_NAMES)
    if paths:
        return paths[0]

    # 마지막 시도: font_manager의 어떤 폰트든 한 개(코딩 폰트 제외)
    for fe in fm.fontManager.ttflist:
        name = (fe.name or "")
        if any(k in name.lower() for k in EXCLUDE_KEYWORDS):
            continue
        if fe.fname and os.path.exists(fe.fname):
            return fe.fname
    return None


def test_pillow_output():
    print("=== Pillow 출력 테스트 ===")
    img = Image.new("RGB", (1400, 420), color="white")
    draw = ImageDraw.Draw(img)

    font_path = _choose_pillow_font_path()
    font = None
    if font_path:
        try:
            font = ImageFont.truetype(font_path, size=48)
            print(f"[Pillow] 적용 폰트: {font_path}")
        except Exception as e:
            print("[Pillow] truetype 로딩 실패:", repr(e))

    if font is None:
        font = ImageFont.load_default()
        print("[Pillow] 한글 폰트를 찾지 못해 기본 폰트 사용 (한글/기호가 깨질 수 있음)")

    draw.text((40, 40), "한글 폰트 테스트 (Pillow)", fill=(0, 0, 0), font=font)
    draw.text((40, 130), TEST_TEXT, fill=(10, 50, 120), font=font)
    draw.text((40, 220), f"(RAW) {RAW_TEST_TEXT}", fill=(80, 80, 80), font=font)

    img.save(PIL_PNG_FILE)
    print(f"저장 완료: {PIL_PNG_FILE}")
    print("-> 이미지에서 한글과 기호가 정상인지 확인하세요.\n")


def main():
    print_env_info()
    try_fix_console_encoding()
    test_console_output()

    # Matplotlib: 안전 폰트 적용
    setup_matplotlib_fonts_safe()
    test_matplotlib_output()

    # Pillow: 이미지 테스트
    test_pillow_output()

    # 파일 IO: UTF-8 테스트
    test_file_io()

    print("=== 테스트 완료 ===")
    print(f"출력 폴더: {OUTPUT_DIR.resolve()}")
    if is_wsl():
        print("\n[WSL 안내]")
        print("- WSL은 Windows 폰트를 자동으로 사용하지 않습니다.")
        print("- 폰트 설치 권장: sudo apt install -y fonts-nanum fonts-noto-cjk fonts-dejavu-core")
        print("- Matplotlib 캐시 초기화: rm -rf ~/.cache/matplotlib/*")


if __name__ == "__main__":
    main()

 

% 보면은 잘못된 내용도 보이나 생성된 코드 그대로 첨부