affaan-m/ECC · error · ValueError

Crop must fit within normalized image coordinates

Error message

Crop must fit within normalized image coordinates

What it means

TasteForge validates that every crop rectangle for a still-image zoom clip consists of exactly four finite numbers and lies fully inside the normalized [0,1] image coordinate space (x,y >= 0, w,h > 0, x+w <= 1, y+h <= 1). filter_graph raises this error before building the ffmpeg filter graph when a start or end crop extends beyond the image. This prevents zoompan from producing out-of-bounds sampling.

Solutions

  1. Normalize the crop: clamp x,y to >= 0 and shrink w,h so x+w <= 1 and y+h > 0, e.g. [0.2, 0.2, 0.5, 0.5]
  2. Convert pixel coordinates to fractions: divide x and w by image width, y and h by image height before calling make_clip
  3. Add an assertion/clamp helper in your pipeline that keeps crop rectangles within the unit square

Example fix

// before
make_clip("in.jpg", "out.mp4", start_crop=[0.4, 0.4, 0.7, 0.7], end_crop=[0.1, 0.1, 0.5, 0.5])  # 0.4+0.7 > 1
// after
make_clip("in.jpg", "out.mp4", start_crop=[0.2, 0.2, 0.5, 0.5], end_crop=[0.1, 0.1, 0.5, 0.5])
Defensive patterns

Strategy: validation

Validate before calling

def valid_crop(c):
    return (isinstance(c, (list, tuple)) and len(c) == 4
            and all(isinstance(v, (int, float)) and math.isfinite(v) for v in c)
            and c[0] >= 0 and c[1] >= 0 and c[2] > 0 and c[3] > 0
            and c[0] + c[2] <= 1 and c[1] + c[3] <= 1)
assert valid_crop(start_crop) and valid_crop(end_crop)

Prevention

When it happens

Trigger: Calling make_clip with a start_crop or end_crop where x<0, y<0, w<=0, h<=0, x+w>1, or y+h>1 (e.g. [0.1, 0.1, 0.9, 0.9] summing to 1.0 exactly is fine, but [0.5, 0.5, 0.6, 0.6] exceeds 1). Also raised when a crop value is non-finite (inf/nan) — though that yields the sibling 'four finite values' error first.

Common situations: Hand-computing crop rectangles in pixel units instead of normalized 0-1 fractions; forgetting that width and height add to x and y; deriving crops from aspect-ratio math that rounds to slightly over 1.0; passing NaN from an upstream computation.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/2621632acf2929a9. Report an issue: GitHub.

Appendix: source

Thrown at skills/taste-application/scripts/tasteforge/media/stills.py:17

"""Animate an image between normalized crop rectangles using local FFmpeg."""

import argparse
import math
import subprocess
from pathlib import Path

from .common import geometry, output_file


def filter_graph(start, end, frames, width, height, fps):
    for crop in (start, end):
        if len(crop) != 4 or any(not math.isfinite(v) for v in crop):
            raise ValueError("Crop must contain four finite values")
        x, y, w, h = crop
        if min(x, y) < 0 or min(w, h) <= 0 or x + w > 1 or y + h > 1:
            raise ValueError("Crop must fit within normalized image coordinates")
    # Coordinates refer to the image after scale-cover to output aspect.
    # Expand each requested rectangle to output aspect, then interpolate its
    # width and center; zoompan clamps the window at image boundaries.
    fraction = f"on/{max(1, frames - 1)}"

    def interpolate(a, b):
        return f"({a}+({b}-{a})*{fraction})"

    zoom = f"1/{interpolate(max(start[2], start[3]), max(end[2], end[3]))}"
    cx = interpolate(start[0] + start[2] / 2, end[0] + end[2] / 2)
    cy = interpolate(start[1] + start[3] / 2, end[1] + end[3] / 2)
    return (
        f"scale={width * 2}:{height * 2}:force_original_aspect_ratio=increase,"
        f"crop={width * 2}:{height * 2},zoompan=z='{zoom}':"
        f"x='iw*{cx}-iw/zoom/2':y='ih*{cy}-ih/zoom/2':"
        f"d={frames}:s={width}x{height}:fps={fps},format=yuv420p"
    )

View on GitHub (pinned to 8321021c54)