Skip to content

Media Settings & Presets

K-Pipe describes every image, video and audio output once, in a DCC-agnostic way. The kpipe.media package (packages/core/src/kpipe/media/) holds the vocabulary: media types, format and codec registries, settings objects, named presets, OCIO color roles, frame ranges and file-type detection. DCC integrations never define their own formats or codecs; they only translate validated settings into their own parameters:

preset + overrides  →  validated settings  →  DCC adapter  →  Blender / Nuke / ffmpeg / OIIO

This means a pipeline TD configures an output once (for example "16-bit half EXR, DWAA 45, scene-linear") and every DCC writes it the same way. Unsupported combinations fail early with a clear message, before anything is rendered.

The core is pure Python. OpenImageIO and PyOpenColorIO are used only when they can be imported (for file probing and OCIO role resolution).

Media type Settings class Used for
image ImageSettings Single images and image sequences
multilayer_image ImageSettings with channels = "all" Multilayer / multi-part EXR (render passes, AOVs)
video VideoSettings Movie files
audio AudioSettings Audio files, or the audio track of a video

Media presets

A preset is a named set of media settings. K-Pipe ships with built-in presets; config bundles add their own or replace built-ins under [media.presets.<name>] in kpipe.toml:

[media.presets.fs_review]
media_type = "video"
container  = "mov"
codec      = "h264"
quality    = "medium"
color      = "display:sRGB/Standard"

# Inherit from another preset and change single fields
[media.presets.fs_plate]
base     = "exr_dwaa"
channels = "rgb"
Key Description
media_type image, multilayer_image, video or audio. Required, unless inherited via base
base Name of another preset (built-in or config) to inherit from. Chains are allowed; cycles are an error
description Optional, informational only
any settings field See the field reference for the media type

A config preset with the same name as a built-in replaces it completely. Use base to extend a preset instead.

How settings are resolved

When an action or output asks for settings, they are resolved in this order. Later steps win:

  1. The preset's base chain, oldest ancestor first.
  2. The preset itself (a config preset replaces a built-in preset of the same name).
  3. Field overrides from the action step, the publish settings or the output entry. Empty values ("") are ignored, so unset override fields never clear a preset value.
  4. Format defaults fill in whatever is still unset (e.g. EXR → 16f and dwaa:45).

The result is validated against the format's capabilities. Invalid settings raise MediaSettingsError, which publish actions report as a PublishError:

Codec 'prores' is not valid for container 'webm' — expected one of: vp9, av1
JPEG has no alpha channel — use channels = 'rgb'
Compression level 5000 for 'dwaa' is out of range 0-1000
Unknown image setting(s) compresion — expected: bit_depth, channels, color, compression, file_format, quality

Note

Changing the format through an override resets the fields that only make sense for the old format. For example, file_format = "png" on top of exr_dwaa drops the EXR bit depth and compression. Changing container to one that can't hold the current codec also switches to the container's default codec.

Value conventions

Value Convention
Bit depth "8", "10", "12", "16" (integer) and "16f", "32f" (float). Numbers are accepted, too: 16 becomes "16f" for EXR (which has no 16-bit integer), "16" for PNG
Compression "<name>" or "<name>:<level>", using OpenImageIO/OpenEXR names, e.g. "zip", "dwaa:45", "zip:9". Names are case-insensitive
Quality A level, "low", "medium", "high" or "lossless", or an explicit number 0–100. Each format/codec maps levels to its own parameters (see quality mapping)
Channels "rgb", "rgba", or "all". "all" writes every channel/layer, making the image a multilayer EXR
Color A ColorSpec string, e.g. "role:scene_linear" or "display:sRGB/Standard"
Frame rate A number or fraction. NTSC rates are stored exactly: 23.976, "23.976" and "24000/1001" all become 24000/1001

Field reference

Field Default Description
file_format "exr" Image format id or any of its extensions (tiff → tif)
bit_depth format default See image formats
compression format default <name>[:<level>]
quality — Level or 0–100. Formats without a quality setting (PNG, DPX, TIFF…) ignore levels but reject numbers
channels "rgba" rgb, rgba, all
color derived Empty → role:scene_linear for float data, role:srgb_texture otherwise
Field Default Description
container "mov" Container id or extension
codec container default First codec listed for the container
profile from quality or codec default ProRes/DNxHR profile, e.g. hq, 4444, hqx
quality high Level or 0–100. For ProRes/DNxHR, levels select a profile and numbers are rejected
bit_depth profile/codec default 8, 10, 12 (16 for FFV1)
chroma profile/codec default 420, 422, 444 (4:2:2 is accepted, too)
alpha false Needs a codec/profile with alpha, e.g. ProRes 4444, VP9, FFV1. ProRes picks a 4444 profile automatically
bitrate — Constant bitrate such as "20M", replacing constant-quality encoding. Long-GOP codecs only
keyframe_interval encoder default Frames between key frames; 1 = all-intra (smooth scrubbing in editing). Long-GOP codecs only
fps — Usually taken from the frame range or project config by the action
audio — A table of audio fields; validated against the container's audio codecs
color role:srgb_texture
Field Default Description
file_format "wav" Ignored when the audio is embedded in a video container
codec format/container default pcm, flac, aac, opus, mp3, vorbis
sample_rate 48000
bit_depth codec default Lossless codecs only: 16, 24, 32f (PCM)
channels 2
bitrate codec default Lossy codecs only, e.g. "256k"

Built-in presets

Defined in BUILTIN_PRESETS (packages/core/src/kpipe/media/presets.py). Values shown are fully resolved.

Images

Preset Format Bit depth Compression / quality Channels Color
exr_dwaa EXR 16f dwaa:45 rgba role:scene_linear
exr_dwab EXR 16f dwab:45 rgba role:scene_linear
exr_zip EXR 16f zip rgba role:scene_linear
exr_piz EXR 16f piz rgba role:scene_linear
exr_32_zip EXR 32f zip rgba role:scene_linear
exr_multilayer EXR (multilayer) 16f dwaa:45 all role:scene_linear
exr_multilayer_lossless EXR (multilayer) 32f zip all role:scene_linear
png_8 PNG 8 zip:6 rgba role:srgb_texture
png_8_rgb PNG 8 zip:6 rgb role:srgb_texture
png_16 PNG 16 zip:6 rgba role:srgb_texture
jpg_review JPEG 8 quality high rgb role:srgb_texture
tif_16 TIFF 16 zip rgba role:srgb_texture
dpx_10_log DPX 10 — rgb role:compositing_log
webp_review WebP 8 quality high rgba role:srgb_texture

Video

Preset Container Codec Profile / quality Bit depth Chroma
prores_proxy mov ProRes proxy 10 422
prores_lt mov ProRes lt 10 422
prores_422 mov ProRes standard 10 422
prores_hq mov ProRes hq 10 422
prores_4444 mov ProRes 4444 12 444
prores_4444_alpha mov ProRes 4444 + alpha 12 444
prores_4444xq mov ProRes 4444xq 12 444
dnxhr_sq mxf DNxHR sq 8 422
dnxhr_hq mxf DNxHR hq 8 422
dnxhr_hqx mxf DNxHR hqx 10 422
dnxhr_444 mxf DNxHR 444 10 444
h264_review mp4 H.264 medium 8 420
h264_high mp4 H.264 high 8 420
h265_review mp4 H.265 medium 10 420
h265_high mp4 H.265 high 10 420
h265_proxy mov H.265 medium, all-intra (keyframe_interval = 1) — editing proxy 10 420
av1_web mp4 AV1 medium 8 420
vp9_web webm VP9 medium 8 420
ffv1_archive mkv FFV1 lossless 10 444

All video presets use role:srgb_texture unless overridden.

Audio

Preset Format Codec Bit depth / bitrate Sample rate
wav_24 wav PCM 24 48000
wav_16 wav PCM 16 48000
flac_24 flac FLAC 24 48000
aac_256 m4a AAC 256k 48000

Format reference

These tables mirror the registries in media/image.py, media/video.py and media/audio.py. Whether a specific DCC can write a combination is listed under DCC support and limitations.

Image formats

Format Extensions Bit depths (default) Compressions (default) Quality Alpha
exr exr, sxr, mxr 16f, 32f (16f) none, rle, zips, zip, piz, pxr24, b44, b44a, dwaa, dwab, htj2k (dwaa:45) levels select a compression yes, multilayer
png png 8, 16 (8) zip (zip:6) — yes
jpg jpg, jpeg, jpe, jfif 8 — 70 / 85 / 95 no
tif tif, tiff 8, 16, 32f (16) none, lzw, zip, packbits (zip) — yes
dpx dpx 8, 10, 12, 16 (10) — — yes
tga tga, tpic 8 none, rle (rle) — yes
webp webp 8 — 50 / 75 / 90, lossless yes
avif avif 8, 10, 12 (8) — 50 / 70 / 85 yes
jxl jxl 8, 16, 32f (8) — 70 / 85 / 95, lossless yes

Compression levels: dwaa/dwab take 0–1000 (OpenEXR's DWA level, 45 ≈ visually lossless), EXR zip/zips take 1–9, PNG zip takes 0–9.

Read-only formats, recognised for detection and loading but never written: hdr (hdr, rgbe), cin, psd (psd, psb), bmp (bmp, dib), gif, tx, jp2 (jp2, j2k, j2c).

Containers and codecs

Container Extensions Video codecs (first = default) Audio codecs
mov mov, qt prores, dnxhr, h264, h265 pcm, aac
mp4 mp4, m4v h264, h265, av1 aac, opus
mxf mxf dnxhr, prores pcm
mkv mkv ffv1, h264, h265, av1, vp9, prores pcm, flac, aac, opus
webm webm vp9, av1 opus, vorbis

Read-only containers: avi, mpg (mpg, mpeg, m2v), mts (mts, m2ts, ts), wmv, flv, ogv, 3gp, r3d, braw.

Codec Bit depths Chroma Alpha Notes
prores 10, 12 422, 444 4444 profiles Intra-frame. Profiles below
dnxhr 8, 10, 12 422, 444 no Intra-frame. Profiles below
h264 8 420 (default), 422, 444 no
h265 8, 10 420 (default), 422, 444 no
av1 8, 10 420 (default), 444 no
vp9 8, 10 420 (default), 444 yes
ffv1 8, 10 (default), 12, 16 420, 422, 444 (default) yes Lossless only
Profile Chroma Bit depths Alpha
ProRes proxy, lt, standard, hq (default) 422 10 no
ProRes 4444, 4444xq 444 10, 12 yes
DNxHR lb, sq, hq (default) 422 8 no
DNxHR hqx 422 10, 12 no
DNxHR 444 444 10, 12 no

Quality mapping

Target low medium high lossless
EXR (sets the compression unless compression is given) dwaa:200 dwaa:100 dwaa:45 zip
JPEG / JPEG XL 70 85 95 — / lossless
WebP 50 75 90 lossless
AVIF 50 70 85 —
ProRes (selects the profile) proxy standard hq —
DNxHR (selects the profile) lb sq hq —
H.264 / H.265 / AV1 / VP9 translated to CRF by each adapter (e.g. ffmpeg H.264: 25 / 21 / 17) —

Audio formats

Format Extensions Codecs
wav wav, wave, bwf pcm
aif aif, aiff pcm
flac flac flac
m4a m4a aac
opus opus opus
mp3, ogg mp3 / ogg, oga read-only

Color

Media settings never store config-specific colorspace names. They store a ColorSpec, written as a string:

Form Example Meaning
role:<role> role:scene_linear An OCIO role or pipeline role, resolved per DCC
<role> data Same as role:data
colorspace:<name> colorspace:ACEScg An explicit colorspace name, used as-is
display:<display>/<view> display:sRGB/Standard A display/view transform (display-referred output)

Supported roles are the standard OCIO roles: scene_linear, rendering, compositing_log, color_timing, color_picking, data, texture_paint, matte_paint, default, reference, aces_interchange and cie_xyz_d65_interchange. Next to those are the DCC roles default_byte, default_float and default_sequencer, and the pipeline role srgb_texture for sRGB-encoded textures and display-referred stills (OCIO has no standard role for it).

When color is empty, image settings default to role:scene_linear for float data (EXR, 32f TIFF…) and role:srgb_texture otherwise; video defaults to role:srgb_texture.

How roles are resolved

When a DCC applies a ColorSpec, resolve_colorspace(spec, dcc) (media/color.py) picks the first match:

  1. An explicit colorspace: name.
  2. A per-DCC alias: [color.roles.<dcc>].
  3. A global alias: [color.roles].
  4. The OCIO config in $OCIO (via PyOpenColorIO, which both launchers provide), else the project's [config] ocio_config_compat. It tries the role itself, then candidate names; OCIO 2 resolves colorspace aliases too.
  5. A fallback name (srgb_texture → sRGB), else the role name itself.

Candidate names tried in the OCIO config:

Role Candidates
srgb_texture srgb_texture, srgb_tx, sRGB - Texture, Utility - sRGB - Texture, sRGB
data raw, Raw, Non-Color, Utility - Raw
scene_linear ACEScg, lin_ap1, Linear Rec.709, linear
compositing_log ACEScct, AgX Log, Cineon

Config aliases are only needed when the OCIO config doesn't define a role, or a DCC needs a different name:

[color.roles]
srgb_texture = "sRGB - Texture"

[color.roles.blender]
srgb_texture = "sRGB"

# Display names used in display:<display>/<view> specs
[color.displays]
sRGB = "sRGB - Display"

[color.displays.blender]
sRGB = "sRGB"

Note

Without $OCIO, roles fall back to their names, which Nuke accepts directly. Blender falls back to its bundled OCIO config.


Formats

Formats are the project-specific part of media output: resolutions under generic keys (working, delivery, review, proxy by convention, any key allowed), so pipeline configs stay project independent. Defined in the bundle's kpipe.toml:

[formats.delivery]
name = "Doris 2K"             # label artists see (Nuke format name, setting dropdowns)
resolution = [2048, 1024]     # optionally [w, h, pixel_aspect]

[formats.working]
name = "Doris 2K Overscan"
base = "delivery"             # inherit the other keys
overscan = [102, 51]          # pixels added per side → 2252x1126

[formats.review]
name = "Doris 1K"
resolution = [1920, 960]
Key Description
name Display name; defaults to the key
resolution [width, height] or [width, height, pixel_aspect] — the image area
overscan [x, y] pixels added on each side; written images have the full size, Nuke registers the image area as the format box
pixel_aspect Default 1.0
base Another format key to inherit from

Actions writing or scaling images take a format field (a key, empty = keep the source resolution):

Action Behaviour
ConfigBlenderRenderOutput Sets the render resolution (at 100 %, incl. overscan and pixel aspect), restored after the publish
ExtractFfmpegSequenceToVideo, ExtractFfmpegVideoToSequence Scales with ffmpeg; fit = fit (letterbox/pillarbox, default), fill (cover and crop) or distort
ExtractBurnIn Scales (same fit modes) before the burn-ins, so text sizes are relative to the target
ConfigNukeWriteOutput No resizing: the publish fails if the image reaching the Write node has another size
SetBlenderFormat (command) Sets the scene's render resolution, e.g. to working

A format setting shows the formats by name in publish UIs:

format = { text = "Format", type = "format", default_value = "review", allow_empty = true, empty_label = "Scene resolution", target = "ConfigBlenderRenderOutput.format" }

In code, kpipe.get_format(key) returns a Format (name, resolution, overscan, full_resolution); kpipe.get_formats() lists them, and kpipe.media.fit_rect(src, dst, mode) computes where an image lands on a format.

Replaces outputs and products

[[attributes.outputs]], [[attributes.products]] and [[attributes.formats]] are gone. Pipelines name a preset (plus overrides) and a format per step, and set their product types themselves (product_type = "{task}_review").


Using presets in pipelines

Every action that writes media follows the same convention. It has a preset field plus flat override fields named like the settings fields. Empty override fields are ignored, so a step only lists what differs from the preset:

# Multilayer EXR render from Blender
[[pipeline.render_blender_cycles.config]]
action = "ConfigBlenderRenderOutput"
preset = "exr_multilayer"

# Review movie from rendered frames, written as .mov instead of .mp4
[[pipeline.blender_render_review_video.extract]]
action    = "ExtractFfmpegSequenceToVideo"
slot_in   = "frames"
preset    = "h264_review"
container = "mov"

# Conform a plate video into a 16-bit half EXR sequence
[[pipeline.plate_conform.extract]]
action      = "ExtractFfmpegVideoToSequence"
preset      = "exr_zip"
channels    = "rgb"

Actions using this convention:

Action Media type Default preset Override fields
ConfigBlenderRenderOutput image png_8 file_format, bit_depth, compression, quality, channels, color, format
ExtractBlenderSequencerFrames image png_8 file_format, bit_depth, compression, quality, channels
ExtractFfmpegSequenceToVideo video h264_high container, codec, profile, quality, bit_depth, chroma, bitrate, keyframe_interval, fps, format, fit
ExtractFfmpegVideoToSequence image png_8 file_format, bit_depth, compression, quality, channels, fps, format, fit

Letting artists choose

Because the fields are flat, publish settings can target them directly. An enum setting is the usual way to offer a fixed choice of presets or quality levels:

[pipeline.blender_render_review_video.settings.video_format]
type          = "enum"
text          = "Format"
default_value = "h264_review"
values        = [["h264_review", "H.264 review (mp4)"], ["prores_hq", "ProRes 422 HQ (mov)"], ["prores_4444", "ProRes 4444 (mov)"]]
target        = "ExtractFfmpegSequenceToVideo.preset"

[pipeline.blender_render_review_video.settings.video_quality]
type          = "enum"
text          = "Quality"
default_value = ""
values        = [["", "Preset default"], ["low", "Low"], ["medium", "Medium"], ["high", "High"]]
target        = "ExtractFfmpegSequenceToVideo.quality"

A setting of type = "media_preset" (optionally with media_type = "video") lists all presets instead of a hand-written values list. The empty "" value keeps the preset's own quality. If the artist's choices form an invalid combination (for example quality = "low" with a lossless-only codec), the action fails with the validation message before anything is encoded.

Published metadata

Integrating a sequence or video stores the media settings with the publish in kpipe-metadata.toml, as a media table inside the version entry:

[[publish.review.main]]
file-type   = "sequence"
version     = 3
file-format = "png"
frame-start = 1001
frame-end   = 1100

[publish.review.main.media]
file_format = "png"
bit_depth   = "8"
channels    = "rgba"
color       = "display:sRGB/Standard"
compression = "zip:6"

Texture sets store one ColorSpec per map in colorspaces (e.g. basecolor = "role:srgb_texture", normal = "role:data"). Load actions read these: LoadBlenderMedia applies media.color to the image datablock, and LoadBlenderTextureSet resolves each map's ColorSpec through OCIO.


DCC support and limitations

The registries describe what a format allows. Each writer supports a subset, and adapters raise MediaSettingsError for combinations they can't write rather than silently writing something else. The mappings below were checked against the DCCs' own documentation and source.

Blender (kpipe_blender/media_blender.py)

Based on the Blender 5.2 Python API (ImageFormatSettings, FFmpegSettings) and Blender's writers in source/blender/imbuf.

  • Images: EXR (single and multilayer), PNG, JPEG, TIFF (8/16 bit), DPX, Targa, WebP and AVIF (8/10/12 bit). Every EXR compression in the registry is supported: none, RLE, ZIPS, ZIP, PIZ, PXR24, B44, B44A, DWAA, DWAB and HTJ2K.
  • DWA level: Blender has no level field; it derives the OpenEXR DWA level from image_settings.quality as level = (100 − quality) × 4.5. The adapter sets quality = 100 − level / 4.5, so dwaa:45 becomes quality 90 (Blender's default).
  • Targa: compression = "rle" writes TARGA, none writes TARGA_RAW.
  • Video: containers mov, mp4, mkv, webm (no MXF). ProRes profiles map to 422_PROXY, 422_LT, 422_STD, 422_HQ, 4444, 4444_XQ. Quality levels map to Blender's CRF presets; numeric quality uses CUSTOM with custom_constant_rate_factor.
  • Color: display/view specs set color_management = "OVERRIDE" with display and view; float formats override the linear colorspace; byte formats follow the scene's view transform.
  • Restore: all changes go through a SettingsRecorder. Actions restore the original scene settings in cleanup().

Not supported in Blender

DNxHR (Blender's DNxHD codec has no profile setting), MXF, JPEG XL, and 32-bit float TIFF.

Nuke (kpipe_nuke/kpipe_nuke_ext/media_nuke.py)

EXR, PNG and DPX knob values come from Foundry's NDK writer sources; knob names from the Nuke 17 Write node reference.

  • Images: EXR, PNG, JPEG, TIFF, DPX, Targa. EXR compressions none, ZIPS, ZIP, PIZ, RLE, B44, B44A, DWAA, DWAB, with dw_compression_level (0–500).
  • Video: mov and mp4 with ProRes (all profiles) and H.264 (quality levels).
  • Color: transformType colorspace with the resolved name, or display with ocioDisplay/ocioView.

Not supported in Nuke

EXR PXR24 and HTJ2K, DWA levels above 500, DNxHR/MXF (Nuke supports DNxHR, but its profile values aren't documented yet), and WebP/AVIF/JPEG XL.

Note

Display/view output on Write nodes has known Nuke issues: the view can reset on script reload (Foundry ID 606354), and OCIO 2 display views are reported not to be usable directly on Write. Rendering through an OCIODisplay node with a colorspace: / raw Write is a workaround.

ffmpeg (kpipe_imgtools/ffmpeg_media.py)

Options and pixel formats checked with ffmpeg -h encoder=<name> (ffmpeg 9.0).

  • Video: every codec in the registry: prores_ks, dnxhd (DNxHR profiles), libx264, libx265, libaom-av1, libvpx-vp9, ffv1. Quality levels map to CRF, e.g. H.264 25 / 21 / 17, H.265 28 / 24 / 20, AV1 40 / 30 / 20, VP9 40 / 33 / 24.
  • Images: PNG, EXR, JPEG, TIFF, DPX, Targa, WebP, AVIF, JPEG XL.
  • Colour: ExtractFfmpegSequenceToVideo converts RGB frames to YUV with the BT.709 matrix in limited range (ffmpeg's default is BT.601) and tags the video from the sequence's colour (color_filter() / color_tags()): always the BT.709 matrix, plus BT.709 primaries and transfer for Rec.709/Rec.1886 displays (sRGB transfer for sRGB). Scene-referred and log colour (e.g. ACEScct) stays untagged; the product's media.color is authoritative. Tags are set with setparams in the filter chain, since encoder options like -color_primaries are overridden by frame properties.

ffmpeg limitations

  • ffmpeg's EXR encoder only writes none, RLE, ZIPS and ZIP. DWAA, DWAB and PIZ can be read but not written, so they fall back to lossless ZIP with a warning. Use OIIO to write DWA-compressed EXRs.
  • 10- and 12-bit DPX and AVIF can't be written with alpha.
  • The DNxHR encoder takes at most 10-bit input; 12-bit settings are encoded as 10 bit with a warning.

OpenImageIO (kpipe_imgtools/oiio_media.py)

OIIO uses the same compression names and bit depths as kpipe.media, so all writable image settings pass straight through, including DWA levels: apply_image_spec(spec, settings) sets the output attributes and image_spec_type(settings) returns the pixel type. oiiotool_output_args(settings) returns the same settings as oiiotool arguments (-d, --compression, --attrib); ExtractBurnIn uses it to keep the sequence's settings when it rewrites frames.

ExtractOiioColorConvert (kpipe_imgtools/actions/extract_oiio_convert.py) converts a sequence with oiiotool in float: optional resize to a format (in the source colour), then the colour transform from the sequence's color to the target color — --colorconvert for roles/colorspaces (role:compositing_log → ACEScct), --ociodisplay for display specs (display:Rec.1886/ACES 2.0) — and writes it with an image preset (default tif_16) into the render folder of its product_type. It always uses the project's compat OCIO config (--colorconfig).


Writing media-aware actions

Custom actions follow the same pattern as the built-ins:

  1. Expose preset plus flat override fields with empty defaults.
  2. Resolve them with resolve_image_settings() / resolve_video_settings() / resolve_audio_settings() and re-raise MediaSettingsError as PublishError.
  3. Apply the settings through an adapter. Never hard-code DCC enum values in actions.
  4. Store the settings and color on the pipeline data (SequencePipelineData.image, VideoPipelineData.video, .color) so integrate actions write them to the publish metadata.
  5. Write changed data back with ctx.set_slot(). get_slot() returns pipeline data (MediaPipelineData subclasses, LayeredSequencePipelineData, FilePipelineData) as a deep copy, so changes to the returned object never reach the slot on their own — and never leak into other slots holding the same data. Other slot contents, such as DCC objects, are returned as is.
from dataclasses import dataclass

import bpy

from kpipe.media import MediaSettingsError, resolve_image_settings
from kpipe.pipeline import ConfigAction, PipelineContext, PublishError

from kpipe_blender.media_blender import SettingsRecorder, apply_image_settings


@dataclass
class ConfigBlenderStillFormat(ConfigAction):
    """Sets the scene's output image format from a media preset."""
    description: str = "Apply image format"
    slot_in: str = "main"
    preset: str = "png_8"
    file_format: str = ""
    bit_depth: str = ""

    def execute(self, ctx: PipelineContext) -> None:
        try:
            settings = resolve_image_settings(self.preset, file_format=self.file_format, bit_depth=self.bit_depth)
            self._recorder = SettingsRecorder()
            ext = apply_image_settings(bpy.context.scene.render.image_settings, settings, self._recorder)
        except MediaSettingsError as e:
            raise PublishError(f"ConfigBlenderStillFormat: {e}") from e

        data = ctx.get_slot(self.slot_in)
        data.file_format, data.image, data.color = ext, settings, settings.resolved_color()
        ctx.set_slot(self.slot_in, data)

    def cleanup(self, ctx: PipelineContext) -> None:
        if hasattr(self, "_recorder"):
            self._recorder.restore()
Adapter Entry points
Blender apply_image_settings(image_settings, settings, recorder), apply_video_settings(render, settings, recorder), blender_colorspace(spec), blender_image_source(path, product)
Nuke apply_write_settings(node, settings), nuke_colorspace(spec)
ffmpeg video_output_args(settings), image_output_args(settings), audio_output_args(settings); each returns ffmpeg.output() kwargs
OIIO apply_image_spec(spec, settings), image_spec_type(settings), image_spec_attributes(settings)

Useful helpers from kpipe.media:

Helper Purpose
is_image_file, is_video_file, is_audio_file, get_media_type Detection by extension; works with sequence paths (shot.####.exr)
probe(path) Reads real properties (size, channels, bit depth, compression, fps) via OIIO or ffprobe
FrameRange, parse_fps, Resolution Frame ranges with exact NTSC rates, resolutions from config
parse_sequence_name, sequence_pattern, replace_frame_placeholder Sequence file naming
resolve_colorspace, resolve_display_view ColorSpec → DCC names

Sources

The DCC limitations above were verified against: