The dark fringe that will not go away
You place a rendered logo with transparency over a bright photograph. Around every edge is a thin dark outline that nobody put there. You blur it, you choke the matte, you try a different export, and it persists.
This is premultiplication, it is the most common bug in compositing, and once you know the arithmetic it takes five seconds to diagnose.
Two conventions for the same file
An RGBA image stores four numbers per pixel. There are two conventions for what the RGB values mean at partially transparent pixels.
Straight (also called unassociated, or unpremultiplied). RGB holds the pixel’s true colour, regardless of transparency. A half-transparent pure red pixel stores R=1, G=0, B=0, A=0.5. The colour is complete; the alpha is a separate instruction.
Premultiplied (associated). RGB has already been multiplied by alpha. The same pixel stores R=0.5, G=0, B=0, A=0.5. Where alpha is zero, RGB is necessarily black, because anything times zero is zero.
Both are valid. Neither is better in general. The file format usually does not tell you which one you have, and that is the whole problem.
Why the fringe appears
The over operation has a form for each convention:
straight: result = FG × α + BG × (1 − α)
premultiplied: result = FG + BG × (1 − α)The premultiplied version omits the multiply because it has already been done. Now take a premultiplied file and composite it with the straight formula. Every edge pixel gets multiplied by alpha a second time. At an edge pixel with alpha 0.5, the foreground contribution is a quarter of what it should be rather than a half. Darker than it should be, only at the edges, exactly proportional to the transparency.
Dark fringe = a premultiplied image treated as straight.
Go the other way (take a straight image and hand it to a premultiplied pipeline) and the foreground is added at full strength on top of a background that has only been reduced by 1 − α. Too much light at the edges.
Bright halo = a straight image treated as premultiplied.
That pair is the entire diagnosis. You do not need to inspect anything; the colour of the fringe tells you which way round the error is.
Where it bites in practice
3D renders are premultiplied. Almost universally. A render from Blender, Cinema 4D or Maya with a transparent film comes out premultiplied, and if your compositor imports it as straight you get the dark edge.
Photoshop’s PNG exports are straight. So are most design-tool exports.
After Effects asks you. On import it shows an “Interpret Footage → Alpha” dialogue with Straight and Premultiplied options and a “Guess” button. The guess is right most of the time and wrong often enough to matter. If you see the fringe, this dialogue is where you fix it.
EXR is almost always premultiplied by convention, and the OpenEXR specification says so.
The rule that actually matters day to day
Unpremultiply before you colour correct. Re-premultiply afterwards.
Here is why. A premultiplied edge pixel’s RGB is already darkened by alpha. If you now apply a gamma or a curve, you are applying it to a value that is part colour and part transparency, and the two get tangled: the correction changes the apparent edge softness, not just the colour. The result is edges that get harder or softer as you grade, which is bewildering until you know the cause.
Every node compositor has Unpremultiply and Premultiply nodes, and the standard shape of a grading branch is unpremult, grade, premult. Nuke’s colour nodes even have an (un)premult by input to do it inline. In After Effects the same issue appears as “the edges got worse after I added the Curves effect”.
Checking it yourself
Sample a pixel in a fully transparent region of your file.
- If RGB is
0,0,0where alpha is0, it is almost certainly premultiplied. - If RGB holds a real colour where alpha is
0, it is straight.
ffprobe -v error -show_entries stream=pix_fmt -of csv=p=0 render.movwill tell you the pixel format, and a viewer that shows the RGB values with alpha disabled will tell you the rest. In Blender’s image editor, switching the display to “Color” rather than “Color & Alpha” shows the raw RGB, which makes this a two-second check.
The free path
Blender’s compositor has Alpha Convert nodes in both directions and renders premultiplied by default. Fusion, inside the free DaVinci Resolve, has AlphaDivide and AlphaMultiply, which are the same operations under their older names. ffmpeg has premultiply and unpremultiply filters. GIMP and Krita both work internally in a defined convention and will tell you which on export. Nothing here needs a licence.
The limitation
Premultiplied images lose information at the edges, and it is not recoverable. At alpha 0.1, the stored RGB is a tenth of the real colour, quantised into 8 bits, so you have roughly 25 distinct levels left to describe that pixel’s colour. Unpremultiplying multiplies it back up by ten and multiplies the quantisation error with it, which is why heavily graded soft edges from 8-bit premultiplied sources go blotchy.
The fix is not a different convention; it is more bit depth. 16-bit float, which is what EXR uses, makes the problem disappear because there are enough levels left at alpha 0.1 to survive the division. This is one of the genuine, concrete reasons professional compositing happens in float rather than in 8-bit.
Every lesson here is open. Your progress is recorded once you pass the Video with AI exam.
Check your understanding
A rendered element composites cleanly. After a Curves adjustment is added to it, the edges become harder and slightly haloed. Why?
Pick the one you would defend. Your answer stays private.
Stuck on something?Ask Deepa, your AI tutor