Opened 13 years ago

Closed 13 years ago

#3704 closed defect (fixed)

msAlphaBlend() does "wrong thing"

Reported by: warmerdam Owned by: warmerdam
Priority: normal Milestone: 6.0 release
Component: MapServer C Library Version: unspecified
Severity: normal Keywords: alpha blending
Cc: tbonfort

Description

For 6.0 msAlphaBlend() has been reimplemented from scratch to do the Porter-Duff "over" operator. However, I believe this is inappropriate for MapServer. In particular, the new implementation of msAlphaBlend() seems to be assuming that the output should be pre-multiplied alpha while the input is not. Pre-multipled alpha means that the destination RGB has already been darkened based on the alpha component.

A simple demonstration of the core problem with the approach is to have a single input RGBA alpha layer with some alpha's between 1 and 254. The output RGBA image will not be the same as the input image.

A case *could* be made that premultiplication is appropriate in the case where there is no output alpha component. But the current code implementation is not conditional on that.

Change History (6)

comment:1 by warmerdam, 13 years ago

Status: newassigned

I have reimplemented msAlphaBlend() to avoid premultiplication (r11034). This is now giving results that I deem appropriate and similar to the old results. I can provide additional justification and test examples if needed.

One thing I have not addressed is the thought of premultiplying the alpha in cases where the destination image does *not* have an alpha. This would be reasonable and I'd be willing to try and add that if desired.

I'm going to leave this for Thomas to comment on before doing more.

comment:2 by warmerdam, 13 years ago

PS. a potential advantage of the new implementation is avoiding floating point math though I have not done any performance comparisons.

comment:3 by warmerdam, 13 years ago

On further review, r11034 seems to interact poorly with other code. For instance saveAsPNG() in mapimageio.c has the following code segment:

                    if(*a) {
                        double da = *a/255.0;
                        unsigned char *pix = (unsigned char*)pixptr;
                        pix[0] = *r/da;
                        pix[1] = *g/da;
                        pix[2] = *b/da;
                        pix[3] = *a;

which seems to assume premultiplied alpha in the rasterBufferObj. Perhaps AGG needs a premultiplied buffer? If so, we need to premultiply when loading raster buffers from raster data sources, and we need to de-pre-multiply when saving through GDAL and possibly other formats.

Waiting for input from Thomas.

comment:4 by tbonfort, 13 years ago

Frank,

would keeping a premultiplied buffer be a problem for the raster handling code?

Both AGG and CAIRO use a premultiplied buffer, and it would seem that our only option is to unpremultiply/premultiply upon entry/exit of the gdal functions.

If this isn't urgent, we should probably go over the problem in montreal to see if we have other options.

Thomas

comment:5 by warmerdam, 13 years ago

I am ok with the raster buffers being pre-multiplied if it is needed for AGG and CAIRO but there will be some effort to bring all the read/write code and raster code into line with that assumption. Ironing it out in Montreal sounds good.

comment:6 by warmerdam, 13 years ago

Resolution: fixed
Status: assignedclosed

Corrected on sprint week, primarily r11218.

Note: See TracTickets for help on using tickets.