fix: ffmpeg fallback for HEIC files that libheif rejects
iPhone photos with depth maps or gain maps have too many auxiliary image references for libheif 1.17, causing pillow-heif to throw "Too many auxiliary image references". process_heic_image() now falls back to ffmpeg when pillow-heif fails — ffmpeg's own HEIC decoder handles these files without issue. Fixes 27/35 HEIC photos that were stuck in failed state. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -102,17 +102,36 @@ def extract_raw_preview(filepath: str) -> Optional[Image.Image]:
|
||||
return None
|
||||
|
||||
def process_heic_image(filepath: str) -> Image.Image:
|
||||
"""Process HEIC/HEIF image formats"""
|
||||
"""Process HEIC/HEIF image formats.
|
||||
|
||||
Tries pillow-heif first (fast, native). Falls back to ffmpeg for
|
||||
files that libheif rejects — e.g. iPhone photos with too many
|
||||
auxiliary image references (depth maps, gain maps).
|
||||
"""
|
||||
try:
|
||||
# Use pillow-heif to open the image
|
||||
img = Image.open(filepath)
|
||||
# Convert to RGB if needed
|
||||
if img.mode != 'RGB':
|
||||
img = img.convert('RGB')
|
||||
return img
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing HEIC file {filepath}: {e}")
|
||||
raise
|
||||
logger.warning(f"pillow-heif failed for {filepath}: {e} — trying ffmpeg")
|
||||
|
||||
# ffmpeg fallback: decode HEIC to PNG in memory.
|
||||
import subprocess
|
||||
from io import BytesIO
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['ffmpeg', '-i', filepath, '-frames:v', '1',
|
||||
'-f', 'image2pipe', '-vcodec', 'png', 'pipe:1'],
|
||||
capture_output=True, timeout=30, stdin=subprocess.DEVNULL,
|
||||
)
|
||||
if result.returncode == 0 and result.stdout:
|
||||
img = Image.open(BytesIO(result.stdout)).convert('RGB')
|
||||
return img
|
||||
logger.error(f"ffmpeg HEIC decode failed for {filepath}: {result.stderr.decode()[-200:]}")
|
||||
except Exception as e2:
|
||||
logger.error(f"ffmpeg fallback failed for {filepath}: {e2}")
|
||||
raise RuntimeError(f"Cannot decode HEIC: {filepath}")
|
||||
|
||||
def process_video_thumbnail(filepath: str) -> Image.Image:
|
||||
"""Extract a still frame from a video file as a PIL Image."""
|
||||
|
||||
Reference in New Issue
Block a user