From bf0d7fd87a70244f976187843649289e339ac83c Mon Sep 17 00:00:00 2001 From: Hyungi Ahn Date: Thu, 9 Apr 2026 13:51:24 +0900 Subject: [PATCH] =?UTF-8?q?fix(tkqc):=20iPhone=20HEIC=20=EC=97=85=EB=A1=9C?= =?UTF-8?q?=EB=93=9C=20=EC=8B=A4=ED=8C=A8=20=E2=86=92=20ImageMagick=20fall?= =?UTF-8?q?back=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 증상: 사용자가 iPhone HEIC 사진을 관리함에서 업로드하면 400 Bad Request. 로그: ⚠️ pillow_heif 직접 처리 실패: Metadata not correctly assigned to image ❌ HEIF 처리도 실패: cannot identify image file 원인: pillow_heif 가 특정 iPhone 이 생성한 HEIC 의 메타데이터를 처리 못함. libheif 를 직접 사용하는 ImageMagick 이 더 범용적이라 system2-report/imageUploadService.js 와 동일한 패턴으로 fallback 추가. 변경: - Dockerfile: imagemagick + libheif1 apt-get 추가 + HEIC policy.xml 해제 - file_service.py: pillow_heif/PIL 실패 시 subprocess 로 magick/convert 호출해서 임시 파일로 JPEG 변환 후 다시 PIL 로 open Co-Authored-By: Claude Opus 4.6 (1M context) --- system3-nonconformance/api/Dockerfile | 9 +++- .../api/services/file_service.py | 43 +++++++++++++++++-- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/system3-nonconformance/api/Dockerfile b/system3-nonconformance/api/Dockerfile index fdb7697..f326cde 100644 --- a/system3-nonconformance/api/Dockerfile +++ b/system3-nonconformance/api/Dockerfile @@ -2,11 +2,16 @@ FROM python:3.11-slim WORKDIR /app -# 시스템 패키지 설치 (gosu: entrypoint 에서 root→appuser 강등용) +# 시스템 패키지 설치 +# - gosu: entrypoint 에서 root→appuser 강등용 +# - imagemagick + libheif: HEIC(iPhone) 등 pillow_heif 가 처리 못하는 이미지 fallback (2026-04-09) RUN apt-get update && apt-get install -y \ gcc \ gosu \ - && rm -rf /var/lib/apt/lists/* + imagemagick \ + libheif1 \ + && rm -rf /var/lib/apt/lists/* \ + && sed -i 's|||' /etc/ImageMagick-6/policy.xml 2>/dev/null || true # Python 의존성 설치 COPY requirements.txt . diff --git a/system3-nonconformance/api/services/file_service.py b/system3-nonconformance/api/services/file_service.py index 5308029..fbb39d3 100644 --- a/system3-nonconformance/api/services/file_service.py +++ b/system3-nonconformance/api/services/file_service.py @@ -84,11 +84,48 @@ def save_base64_image(base64_string: str, prefix: str = "image") -> Optional[str print(f"✅ HEIF 재시도 성공: {image.format}, 모드: {image.mode}, 크기: {image.size}") except Exception as heif_e: print(f"❌ HEIF 처리도 실패: {heif_e}") - print("❌ 지원되지 않는 이미지 형식") - raise e + image = None # ImageMagick fallback 시도 else: print("❌ HEIF 지원 라이브러리가 설치되지 않거나 처리 불가") - raise e + + # ImageMagick fallback (pillow_heif 가 특정 iPhone HEIC 메타데이터를 처리 못하는 경우) + if image is None: + print("🔄 ImageMagick 으로 fallback 시도...") + try: + import subprocess + import tempfile + with tempfile.NamedTemporaryFile(suffix='.bin', delete=False, dir='/tmp') as tmp_in: + tmp_in.write(image_data) + tmp_in_path = tmp_in.name + tmp_out_path = tmp_in_path + '.jpg' + # convert 는 ImageMagick 6, magick 은 ImageMagick 7 + cmd = None + for binary in ('magick', 'convert'): + try: + subprocess.run([binary, '-version'], capture_output=True, timeout=5, check=True) + cmd = binary + break + except (FileNotFoundError, subprocess.CalledProcessError, subprocess.TimeoutExpired): + continue + if not cmd: + raise Exception("ImageMagick not installed") + result = subprocess.run( + [cmd, tmp_in_path, tmp_out_path], + capture_output=True, timeout=30, text=True + ) + if result.returncode != 0: + raise Exception(f"ImageMagick 변환 실패: {result.stderr[:200]}") + image = Image.open(tmp_out_path) + image.load() # 파일 삭제 전 강제 로드 + print(f"✅ ImageMagick fallback 성공: {image.format}, 모드: {image.mode}, 크기: {image.size}") + try: + os.unlink(tmp_in_path) + os.unlink(tmp_out_path) + except OSError: + pass + except Exception as magick_e: + print(f"❌ ImageMagick fallback 실패: {magick_e}") + raise e # 원래 PIL 에러를 올림 # 이미지가 성공적으로 로드되지 않은 경우 if image is None: