Skip to content

Image(s)

🖼️ Image

1. Create an Image object

from lite_media_core import Image

img = Image("path/to/image.png")

if img.exists:  # Check if online?
    width, height = img.resolution
    print("Resolution:", img.resolution)
    print("Frame Range:", img.frame_range)
    print("Metadata:", img.metadata)

Lazy Loading: metadata is loaded only when accessing a property for the first time.

Frame Extraction: if the filename includes a frame number (e.g. image.0125.png), the frame_range is automatically set.

2. Check image channels

TODO

3. Image MIME types

Checking the media type (instead of the file extension) provides a more reliable detection — it handles casing (JPG vs jpg) and common extension variants (jpg vs jpeg).

from lite_media_core import Image

jpg_img = _image_media.ImageMedia("path/to/image.JPG")
jpeg_img = _image_media.ImageMedia("path/to/image.jpeg")

assert jpg_img.type == jpeg_img.type  # "image"
assert jpg_img.sub_type == jpeg_img.sub_type  # "jpeg"

4. Anamorphic resolution

from lite_media_core import Image

img = Image("path/to/anamorphic_image.exr")

if img.resolution.pixel_aspect_ratio != 1.0:
    print(f"Image {img} is anamorphic.")

🎞️ ImageSequence

ImageSequence groups a series of numbered images (e.g., img.1001.exr, img.1002.exr, etc.) into a single logical media object. It supports validation, frame iteration, resolution consistency checking, and missing frame detection.

1. Create an ImageSequence object

You can create an ImageSequence from:

from lite_media_core import ImageSequence

# From a path
seq = ImageSequence("path/to/sequence.1001-1010#.exr")

# From a list of images
seq_from_list = ImageSequence.from_list([
    "path/to/frame.0000.exr",
    "path/to/frame.0001.exr",
    "path/to/frame.0002.exr",
])

You can create an image sequence from path variations.

from lite_media_core import ImageSequence

seq1 = ImageSequence("/path/to/sequence.1001-1010#.exr")
seq2 = ImageSequence("/path/to/a/sequence.%04d.ext [1-2, 9-10]")
seq3 = ImageSequence("/path/to/a/sequence.@@@.ext 1-5")
seq4 = ImageSequence("/path/to/a/sequence_1-5.ext")

2. Sequence properties

When accessing properties like resolution, metadata, or mime_type, ImageSequence automatically delegates the call to the first available frame. This ensures quick access without scanning the entire sequence.

from lite_media_core import ImageSequence

seq = ImageSequence("path/to/sequence.1001-1010#.exr")

# These properties are delegated to the first frame internally
print("Resolution:", seq.resolution)
print("Metadata:", seq.metadata)
print(f"MIME type: {seq.type}/{seq.sub_type}.")

3. Format sequence path

# Example output: path/to/sequence.####.exr 1001-1010
print(seq.path)

print(seq.head)   # "sequence."
print(seq.tail)   # ".exr"
print(seq.padding)  # 4

also using some helpers:

from lite_media_core import sequence
from lite_media_core import ImageSequence

seq = ImageSequence("path/to/sequence.1001-1010#.exr")
seq.format(sequence.PredefinedFormat.FFMPEG)  # path/to/sequence.%04d.exr

4. Iterate over the sequence

for frame in seq:
    print(frame.path)  # frame in an Image object

Access a specific frame directly:

from lite_media_core import ImageSequence

seq = ImageSequence("path/to/sequence.1001-1010#.exr")

print(seq.get_frame_path(1005))  # path/to/sequence.1005.exr

5. Detect missing or corrupted frames

Loop over the missing frames:

from lite_media_core import ImageSequence

seq = ImageSequence("path/to/sequence.1001-1010#.exr")

for frame in seq.missing:
    print(f"Missing frame: {frame.path}")

Validate a sequence with the built-in validate():

from lite_media_core import ImageSequence

try:
    seq = ImageSequence("path/to/inconsistent_sequence.1001-1005#.exr")
    seq.validate()

except ValueError as e:
    print(f"Inconsistent sequence detected: {e}")

6. Check inconsistent resolution

You can use the built-in validate() method (see above).

You can also validate frame resolutions asynchronously for better performance on large sequences:

import asyncio
from lite_media_core import media


async def _check_resolution(frame, expected_resolution):
    """Async check for a single frame."""
    return frame.resolution == expected_resolution


async def validate_sequence_resolution(seq: media.ImageSequence):
    """Async validate that all frames match the same resolution."""

    # Use the first available frame as the reference
    expected_resolution = seq.resolution

    tasks = [
        _check_resolution(frame, expected_resolution)
        for frame in seq
    ]

    results = await asyncio.gather(*tasks)

    # Return frames that mismatch.
    return [frame for frame, is_valid in zip(seq, results) if not is_valid]


async def main():
    seq = media.ImageSequence("path/to/sequence.1001-1020#.exr")
    mismatched_frames = await validate_sequence_resolution(seq)

    if mismatched_frames:
        print(f"Frames with wrong resolution: {mismatched_frames}.")
    else:
        print("All frames have consistent resolution.")

# Run
asyncio.run(main())