Drop noisy ffmpeg fallback for non-HEIC images, quiet ffmpeg output

A corrupt TIFF in production produced a wall of ffmpeg error output:
pyvips could not decode it, the generic ffmpeg fallback was tried, and
ffmpeg's TIFF decoder failed just the same — with banner, configuration
and stream-mapping spam included.

- Non-HEIC images are now decoded by pyvips only; a pyvips failure
  raises a clean one-line ValueError ("cannot decode image: ...", a 422
  like any other undecodable file) instead of invoking ffmpeg. The
  ffmpeg path is kept for HEIC/HEIF, where pyvips genuinely falls short
  (tile assembly, HDR metadata).
- ffmpeg runs with -hide_banner -loglevel error -nostats: error output
  is still shown on failure, without the version/configuration/progress
  noise. The -s insertion index no longer depends on fixed positions.
This commit is contained in:
2026-08-11 05:29:32 +00:00
parent 36764885ed
commit 69d58f99e3
+14 -9
View File
@@ -213,6 +213,11 @@ def _image_via_ffmpeg(path: Path, maxsize: int, quality: int) -> bytes:
tmp_path = tmp_f.name tmp_path = tmp_f.name
cmd = [ cmd = [
"ffmpeg", "ffmpeg",
# Keep error messages, drop the banner/config/stream-mapping spam.
"-hide_banner",
"-loglevel",
"error",
"-nostats",
"-y", "-y",
"-i", "-i",
str(path), str(path),
@@ -233,8 +238,9 @@ def _image_via_ffmpeg(path: Path, maxsize: int, quality: int) -> bytes:
new_w = int(w * scale) new_w = int(w * scale)
new_h = int(h * scale) new_h = int(h * scale)
# insert -s <wxh> right after the input file # insert -s <wxh> right after the input file
cmd.insert(4, "-s") input_index = cmd.index(str(path)) + 1
cmd.insert(5, f"{new_w}x{new_h}") cmd.insert(input_index, "-s")
cmd.insert(input_index + 1, f"{new_w}x{new_h}")
try: try:
try: try:
# stdin=DEVNULL is critical: ffmpeg must not inherit the worker's # stdin=DEVNULL is critical: ffmpeg must not inherit the worker's
@@ -285,9 +291,10 @@ def process_image_pyvips(path, *, maxsize, quality):
height=height, height=height,
) )
# Other image formats: pyvips first, ffmpeg fallback. # Other image formats: pyvips only. ffmpeg is not a useful fallback
# here — when pyvips cannot decode a file, ffmpeg's image decoders
# cannot either, and their failure output is far noisier.
load_opts = {"access": "sequential"} load_opts = {"access": "sequential"}
orig_w = orig_h = None
try: try:
img = pyvips.Image.new_from_file(str(path), **load_opts) img = pyvips.Image.new_from_file(str(path), **load_opts)
img = img.autorot() img = img.autorot()
@@ -301,11 +308,9 @@ def process_image_pyvips(path, *, maxsize, quality):
effort=AVIF_FAST_EFFORT, effort=AVIF_FAST_EFFORT,
keep="none", keep="none",
) )
backend = "pyvips" except pyvips.error.Error as e:
except pyvips.error.Error: raise ValueError(f"cannot decode image: {e}") from e
orig_w, orig_h = None, None backend = "pyvips"
ret = _image_via_ffmpeg(path, maxsize, quality)
backend = "ffmpeg"
t_end = perf_counter() t_end = perf_counter()
return ret, PreviewResponse( return ret, PreviewResponse(