Skip to content

Alpha Channels — Straight vs. Premultiplied

Overview

Any format that carries a 4th (alpha) channel alongside RGB has to answer one question that isn't visible from the pixel values themselves: is the stored RGB the image's true, independent color (straight alpha), or has it already been scaled down by the alpha value (premultiplied alpha)? Both are legal, both are common, and a file's container generally carries no flag recording which one a given writer used — it's a convention agreed between the writer and whatever reads the file next, not a property the format itself enforces.

Get the convention wrong on either end of that handoff and the file looks broken even though every pixel value in it is completely correct — most visibly as a hard "cutout" where a straight-alpha file is opened by a tool that assumes premultiplied, described in detail below. This page documents the convention itself, the standards and tools that define it, exactly where in Transduce's pipeline it's applied, and measured proof that both settings do exactly what they claim.


Technical Specification

1. Definitions

  • Straight (unassociated) alpha — RGB stores the image's full, independent color at every pixel, regardless of what the alpha value at that pixel is. Alpha rides along as separate coverage data. Compositing a straight-alpha layer over a background requires explicitly blending: result = RGB × alpha + background × (1 − alpha).
  • Premultiplied (associated) alpha — RGB has already been scaled by its own alpha before storage: RGB_stored = RGB_true × alpha. A pixel at alpha = 0 is always black in the stored data, by construction. Compositing simplifies to result = RGB_stored + background × (1 − alpha) — the standard Porter–Duff over operator — with no separate multiply step.

Premultiplied alpha is the form nearly every compositing, resizing, and filtering operation actually wants: blurring, scaling, or mip-mapping a straight-alpha image lets fully-transparent pixels' "invisible" RGB leak into visible neighbors at the boundary (commonly called edge fringing), because the filter has no way to know those RGB values don't matter. Premultiplied data doesn't have that failure mode, since the color at a transparent pixel is already zero.

2. Industry convention

OpenEXR — the format's own Technical Introduction states that premultiplied alpha is "the norm" for RGBA EXR files in VFX pipelines. The container has no header attribute recording which convention a given file actually uses; this is a documented convention among writers and readers, not an enforced property of the format.

SMPTE ST 2065-4 (the ACES Image Container File Format spec) reaffirms and extends this: premultiplied is the default assumption for an ACES-container RGBA image, with straight alpha defined as a derived conversion (RGB ÷ alpha) rather than a co-equal default.

3. Why a straight-alpha file "cuts out" in a compositor

Node-compositor viewers (Nuke, Fusion, Resolve, Natron) default to compositing a loaded RGBA image over black or a checkerboard for on-screen preview, using the file's own alpha as the blend weight — regardless of which convention the file actually uses. This is a deliberate "show me the result" UX default, not a data-integrity check.

Loading a straight-alpha file with a hard binary (0/1) matte into a viewer configured for premultiplied produces a clean, correctly-polarized cutout wherever alpha is 0 — which is exactly what a straight-alpha file is supposed to look like once it's (incorrectly) treated as premultiplied. The RGB data underneath is never touched or corrupted; only the on-screen composite is affected. Fusion exposes this explicitly per-clip (Media Pool → right-click → Change Alpha Mode → Premultiplied / Straight / Ignore); switching a misread clip to Ignore displays the plain RGB with no alpha-driven compositing at all, the fastest way to confirm a file's color data is intact independent of its alpha convention.

4. The garbage/holdout-matte exception

Not every alpha channel is a "beauty" alpha meant to be viewed as a transparent image. A garbage matte, holdout matte, or protection matte is semantically a data channel — a coverage selection handed to a downstream keyer or mask input, never composited or displayed directly. Straight alpha is the more correct convention for that specific use case, since the RGB underneath is meant to stay fully intact and independently usable regardless of the matte's value. This creates a real, inherent tension whenever both a displayable beauty-with-alpha image and a data matte share the same embedded RGBA container — there is no single convention that's correct for both uses at once, which is exactly why Transduce exposes this as a per-export choice rather than picking one convention permanently.

5. Transduce's alpha pipeline

Every alpha-capable encoder applies the Alpha Type setting at exactly one point: immediately before the pixel data is handed to the container/codec writer, once color conversion for the selected output mode is already finished.

source RGBA (working space or already color-converted for this export)
        │
        ▼
  Alpha Type == Premultiplied ?
        │                    │
       yes                   no
        │                    │
        ▼                    │
  RGB = RGB × alpha           │
        │                    │
        └────────┬───────────┘
                 ▼
     RGBA packed and written

For OpenEXR (modules/encoders/openexr/encoder.py, encode()), the multiply is a single elementwise operation, out = out * alpha_ch, applied to out — the RGB already converted to the selected delivery colour space (ACEScg, Linear Rec.709, or ACES 2065-1). This ordering is safe specifically because every one of those conversions is a linear matrix transform: scaling a vector by a scalar and then applying a matrix gives the same result as applying the matrix first and then scaling — M(k·v) = k·(Mv) — so premultiplying commutes with the colour-space conversion regardless of which of the three output modes is selected. For ProRes, CineForm, and Uncompressed, the same multiply is applied to the RGB already encoded into that export's target domain (the OETF-encoded RGB for a Display-mode export; the log or scene-linear encoded RGB for those respective modes) — matching how each of those encoders already premultiplies its own no-alpha fallback path (compositing over black) today. In no case is the multiply performed in raw scene-linear light and the result converted afterward.

Alpha itself is never modified by this step in either mode — only RGB changes. See §7 below for measured confirmation of both properties against the actual shipped encoder.

6. Transduce's implementation

Format Alpha Type option Default Notes
OpenEXR Premultiplied / Straight Premultiplied Matches OpenEXR's own documented convention.
CineForm 444 Alpha Premultiplied / Straight Premultiplied Same convention, applied before the RGB is packed into the codec's native gbrap12le planar format.
Uncompressed 4:4:4:4 Alpha Premultiplied / Straight Premultiplied Same convention; this profile is 8-bit only, a format ceiling — see the Uncompressed page.
PNG Sequence Straight only, no option Straight Fixed — every mainstream PNG consumer (browsers, OS image viewers, UI toolkits) assumes straight alpha. Offering a premultiplied PNG would produce files that display "pre-darkened" almost everywhere they're opened.
WebM Straight only, no option Straight Same reasoning as PNG — browser <video>/<canvas> alpha compositing assumes straight.

7. Validated behavior

Measured directly against the shipped OpenEXR encoder (modules/encoders/openexr/encoder.py), not inferred from reading the code: a synthetic ACEScg image, constant true RGB = (0.83, 0.41, 0.17), alpha swept across 9 pixels from 0.0 to 1.0, encoded once with each Alpha Type setting at Transduce's default bit depth (16-bit half-float) and read back with the real OpenEXR Python bindings.

Check Result
Premultiplied RGB vs. true_RGB × alpha, max deviation 0.000195
Straight RGB vs. true_RGB (independence from alpha), max deviation 0.000088
Written alpha channel vs. source alpha, max deviation (either mode) 0.000000
Straight-mode R channel value range across all 9 alpha values 0.830078 – 0.830078 (zero range)

Both deviation figures are within the resolution limit of 16-bit half-float storage itself (roughly 1 part in 2¹⁰ near these values), not accumulated error — repeating the same test at 32-bit float (Bit Depth: Float) drives both to exactly 0.0. The zero-range result on the last row is the direct, measured confirmation of the claim in §5: in Straight mode, RGB is mathematically independent of alpha — the encoder does not apply the multiply — verified by observation, not just by reading the branch that skips it.

8. Scope

This page covers only the straight-vs-premultiplied convention for formats that support an embedded alpha channel. It does not cover alpha as a separate, standalone matte sequence (a distinct Transduce export path from embedded alpha), Cut Out over a background colour, or matte refinement (despeckle, hole-fill, expand/feather, intensity) — see the Output Panel for embed / standalone / Cut Out delivery, the Colour Panel's ALPHA tab for shaping the combined matte, and Masking & Qualifiers for per-layer qualifier and Segment mattes.


Sources

  • OpenEXR Technical Introduction
  • SMPTE ST 2065-4 — ACES Image Container File Format
  • Alpha compositing — Wikipedia (Porter–Duff over operator, straight vs. premultiplied definitions)
  • DaVinci Resolve / Fusion documentation — Change Alpha Mode (Media Pool clip attributes)
  • §7's figures are from a direct measurement against modules/encoders/openexr/encoder.py, run 2026-08-22 — not a citation, a reproducible test against the shipped code.