- 이미지 압축: 삼성/네이버 브라우저 호환, URL.createObjectURL 방식으로 메모리 절감, 대용량 PNG/HEIC 처리, blob 유효성 검증, 순차 압축으로 모바일 OOM 방지 - HEIC/HEIF 지원: pillow-heif 서버사이드 변환, Pillow 12.2.0 업그레이드 - 조치 페이지: '조치 완료 저장' 단일 버튼으로 단순화 - 재조치 흐름: 관리자 재조치 요청 시 이전 조치 이력을 번호 카드로 순차 표시 - 신고 순번: 전체 기준 ROW_NUMBER(oldest=1) 순번 표시, 삭제 gap 제거 - 모바일 탭바: position:fixed 적용으로 nav 하단 흰 여백 제거 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
59 lines
2.1 KiB
Python
59 lines
2.1 KiB
Python
import os, uuid, io, qrcode
|
|
from PIL import Image
|
|
from fastapi import UploadFile
|
|
|
|
# HEIC/HEIF 지원 등록 (pillow-heif)
|
|
try:
|
|
from pillow_heif import register_heif_opener
|
|
register_heif_opener()
|
|
_HEIF_SUPPORTED = True
|
|
except ImportError:
|
|
_HEIF_SUPPORTED = False
|
|
|
|
UPLOAD_DIR = os.getenv("UPLOAD_DIR", "/uploads")
|
|
|
|
# 브라우저에서 표시 불가능한 포맷 → 서버에서 JPEG 변환
|
|
_CONVERT_EXTS = {".heic", ".heif", ".avif"}
|
|
|
|
def save_upload(file: UploadFile, sub_dir: str = "general") -> str:
|
|
"""파일을 저장하고 /uploads 기준 상대 경로 반환.
|
|
HEIC/HEIF 등 브라우저 비호환 포맷은 JPEG로 변환 후 저장."""
|
|
raw = file.file.read()
|
|
ext = os.path.splitext(file.filename or "file")[1].lower() or ".jpg"
|
|
folder = os.path.join(UPLOAD_DIR, sub_dir)
|
|
os.makedirs(folder, exist_ok=True)
|
|
|
|
if ext in _CONVERT_EXTS:
|
|
# HEIC/HEIF → JPEG 변환
|
|
try:
|
|
img = Image.open(io.BytesIO(raw))
|
|
if img.mode in ("RGBA", "P", "LA"):
|
|
img = img.convert("RGB")
|
|
elif img.mode != "RGB":
|
|
img = img.convert("RGB")
|
|
buf = io.BytesIO()
|
|
img.save(buf, format="JPEG", quality=88, optimize=True)
|
|
raw = buf.getvalue()
|
|
ext = ".jpg"
|
|
except Exception:
|
|
pass # 변환 실패 시 원본 그대로 저장
|
|
|
|
filename = f"{uuid.uuid4().hex}{ext}"
|
|
filepath = os.path.join(folder, filename)
|
|
with open(filepath, "wb") as f:
|
|
f.write(raw)
|
|
return f"/uploads/{sub_dir}/{filename}"
|
|
|
|
def generate_qr(charger_id: str, domain: str) -> str:
|
|
"""QR 이미지를 저장하고 /uploads 기준 경로 반환"""
|
|
url = f"https://{domain}/report/{charger_id}"
|
|
qr = qrcode.QRCode(version=1, box_size=10, border=4)
|
|
qr.add_data(url)
|
|
qr.make(fit=True)
|
|
img = qr.make_image(fill_color="black", back_color="white")
|
|
folder = os.path.join(UPLOAD_DIR, "qr")
|
|
os.makedirs(folder, exist_ok=True)
|
|
filepath = os.path.join(folder, f"{charger_id}.png")
|
|
img.save(filepath)
|
|
return f"/uploads/qr/{charger_id}.png"
|