Premultiplied Alpha
Scale a cut-out and its edge comes out wrong unless the colour was multiplied by its own coverage before anything averaged it. That has been known since 1984, and the two people who worked it out raised the obvious objection to their own fix in the same paper: multiplying first costs precision, and costs most of it exactly where the coverage is nearly nothing. They judged the loss very minor and moved on, and nobody since has put a number on it. There are only 65,536 pairs of an eight-bit colour and an eight-bit alpha, so this page counts them.
New to what the fourth channel in an image is? Start here
A pixel in a cut-out carries a colour and one more number, alpha, which says how much of that pixel the object covers. Fully inside the shape it is 1, outside it is 0, and along the edge it is a fraction, because the edge does not run along the pixel grid.
Anything that resizes, blurs or scales an image averages neighbouring pixels. The question this page is about is what happens to that extra number when you do, and the answer is that the colour has to be weighted by it before the average, not after. Doing it in the wrong order gives an edge that is visibly wrong, and the wrongness has a direction: toward whatever colour was sitting in the transparent pixels, which is usually black.
A grid of dots on a clock
A screen is a grid of coloured dots, redrawn from top to bottom on a fixed beat. Everything drawn on it is a decision about which dots and what colour, made before the beat arrives.
The clock is the part that makes this hard. It does not wait, and it does not care whether the drawing was finished, so a picture that took too long is shown half-done. Most of the machines in this topic exist because of that deadline rather than because of the picture.
The machine for this idea on its own is Eight Sprites, if you would rather press it than read about it.
The edge of the cut-out is wrong unless you multiply before you blend
1 One edge texel and its transparent neighbour, averaged in both of the two possible orders
One pixel on the edge of a cut-out, next to a pixel the object does not reach. Move the edge across the pixel and watch the two filters disagree. Both are averaging the same two texels. Premultiplied scales each colour by its own coverage before anything averages it; straight averages the colour and the coverage apart. That is the only difference between them.
| order | alpha | colour | off by |
|---|
2 The same edge against the coverage it actually has, computed a third way, which is what makes one of those two answers the wrong one
Calling one of those two answers wrong needs an answer that came from neither. This one comes from coverage: the edge is sampled, each sample is inside the object or outside it, and the result is the fraction inside together with the object's own colour. No filter is involved. Then both filtered edges are composited over a background, which is where the difference stops being arithmetic and becomes a fringe.
| coverage | correct | straight | off by |
|---|
3 What the fix costs, counted over every colour and alpha that eight bits can hold
Porter and Duff raised the objection to their own representation and answered it: storing the product, they wrote, forces "only a very minor loss of precision", though on recovering a colour, "as alpha approaches 0, the precision falls off sharply." Eight bits of colour and eight bits of alpha is 65,536 pairs, so the objection can simply be counted.
| quantity | value |
|---|
These ran in this browser when the page loaded. Each claim, whether it held, and the number behind it.
| claim | held | measured |
|---|---|---|
| averaging the same two texels in the two possible orders gives two different colours | yes | a white object half covering the pixel filters to 255.0 one way and 127.5 the other, at the same alpha of 127.5 |
| the coverage integral picks one of them, and it is not the obvious one | yes | integrating the edge gives colour 255 at alpha 127.5; the premultiplied filter is off by 0.0 and the straight one by 127.5 |
| the premultiplied filter matches the integral at every coverage, not at one | yes | 63 edge positions swept across the pixel, and the premultiplied result equals the integrated one at all of them |
| the error is a dark fringe, worst where the edge is half way across | yes | a white edge over a white background should composite to 255 and comes out at 191, a difference of 64 levels at 50% coverage |
| what leaks into the edge is whatever colour was left in the transparent texels | yes | with black in the transparent texels the fringe is 64 levels; fill those same texels with the object's own colour and the straight filter is exactly right, which is what colour-bleeding tools do and why they work |
| the fix is not free, and the cost is countable rather than a matter of opinion | yes | 32,895 of 65,536 colour-and-alpha pairs survive an eight-bit premultiply and unpremultiply unchanged, which is 50.2%; the other 32,641 come back as a different colour |
| the loss falls off sharply as alpha approaches zero, exactly as the paper says | yes | at alpha 255 all 256 colours survive; at alpha 1 only 2 do, because a premultiplied colour at alpha a can take only a+1 distinct values and there is nowhere for the rest to go |
| every number here is linear light, and gamma is a different machine | yes | filtering gamma-encoded values introduces a second and larger error that has nothing to do with alpha; this page works in linear light throughout and links to the machine about the other one rather than mixing the two failures into one demonstration |
| the count is a fact about eight bits, not an argument against premultiplying | yes | a pipeline that premultiplies at sixteen bits or in floating point loses none of this, and the alternative is not lossless either: it is wrong at every edge rather than imprecise at low alpha |
What is real here, and what is not
Everything here is linear light, and gamma is a different machine
Filtering gamma-encoded values introduces a second error, larger than this one and unrelated to alpha, and mixing the two into one demonstration is how both end up half-explained. This page works in linear light throughout. The other failure has its own machine on this site and this one links to it rather than restating it.
The integrated edge is a model of a hard-edged object, not of every edge
The witness this page uses to break the tie is coverage: an edge sampled across a pixel, each sample inside or outside, integrated. That is exactly right for an opaque object with a hard boundary, which is the case where the two filters differ most and the case the argument is about. A semi-transparent object, or two objects overlapping inside one pixel, needs an assumption about how their coverages interact, and Porter and Duff spend a section of the paper on precisely that. None of it is modelled here.
The count is a fact about eight bits, not an argument against premultiplying
Roughly half of all colour-and-alpha pairs do not survive an eight-bit premultiply and unpremultiply. A pipeline that premultiplies at sixteen bits or in floating point loses none of it. And the alternative is not lossless either -- it is wrong at every edge in the image rather than imprecise at low alpha, which is a worse trade, not a better one. The number is here because it had never been put on the page, not because it changes the answer.
Colour is undefined where alpha is zero, and this page says so rather than printing a value
A premultiplied pixel at alpha zero carries no colour at all: every colour multiplies to the same nothing. Unpremultiplying it is a division by zero and the honest output is a refusal. Tools that fill those texels with a neighbour's colour are not recovering anything, they are inventing something useful, and that is a different operation with a different name.
The filter here is a plain average of two texels
Real scaling uses wider filters with weights that are not all equal, and a mipmap chain applies one repeatedly. The order-of-operations error this page is about is the same at every filter width, because it is a property of multiplying before summing rather than of the weights. Using the simplest possible filter makes the arithmetic checkable by hand, which is the whole reason it was chosen.
The paper's own words are quoted, and it is a scan
The 1984 paper is archived here as text extracted from a scanned PDF, and the extraction has visible errors elsewhere on the page it was taken from. The two sentences quoted are quoted exactly as the extraction has them, character for character, rather than tidied into what they obviously mean.