art_blend_pixel_8_inline(byte *gs_restrict dst, const byte *gs_restrict backdrop,
                  const byte *gs_restrict src, int n_chan, gs_blend_mode_t blend_mode,
                  const pdf14_nonseparable_blending_procs_t * pblend_procs,
                  pdf14_device *p14dev)
{
    int i;
    byte b, s;
    bits32 t;

    switch (blend_mode) {
        case BLEND_MODE_Normal:
        case BLEND_MODE_Compatible:	/* todo */
            memcpy(dst, src, n_chan);
            break;
        case BLEND_MODE_Multiply:
            for (i = 0; i < n_chan; i++) {
                t = ((bits32) backdrop[i]) * ((bits32) src[i]);
                t += 0x80;
                t += (t >> 8);
                dst[i] = t >> 8;
            }
            break;
        case BLEND_MODE_Screen:
            for (i = 0; i < n_chan; i++) {
                t =
                    ((bits32) (0xff - backdrop[i])) *
                    ((bits32) (0xff - src[i]));
                t += 0x80;
                t += (t >> 8);
                dst[i] = 0xff - (t >> 8);
            }
            break;
        case BLEND_MODE_Overlay:
            for (i = 0; i < n_chan; i++) {
                b = backdrop[i];
                s = src[i];
                if (b < 0x80)
                    t = 2 * ((bits32) b) * ((bits32) s);
                else
                    t = 0xfe01 -
                        2 * ((bits32) (0xff - b)) * ((bits32) (0xff - s));
                t += 0x80;
                t += (t >> 8);
                dst[i] = t >> 8;
            }
            break;
        case BLEND_MODE_SoftLight:
            for (i = 0; i < n_chan; i++) {
                b = backdrop[i];
                s = src[i];
                if (s < 0x80) {
                    t = (0xff - (s << 1)) * art_blend_sq_diff_8[b];
                    t += 0x8000;
                    dst[i] = b - (t >> 16);
                } else {
                    t =
                        ((s << 1) -
                         0xff) * ((bits32) (art_blend_soft_light_8[b]));
                    t += 0x80;
                    t += (t >> 8);
                    dst[i] = b + (t >> 8);
                }
            }
            break;
        case BLEND_MODE_HardLight:
            for (i = 0; i < n_chan; i++) {
                b = backdrop[i];
                s = src[i];
                if (s < 0x80)
                    t = 2 * ((bits32) b) * ((bits32) s);
                else
                    t = 0xfe01 -
                        2 * ((bits32) (0xff - b)) * ((bits32) (0xff - s));
                t += 0x80;
                t += (t >> 8);
                dst[i] = t >> 8;
            }
            break;
        case BLEND_MODE_ColorDodge:
            for (i = 0; i < n_chan; i++) {
                b = backdrop[i];
                s = 0xff - src[i];
                if (b == 0)
                    dst[i] = 0;
                else if (b >= s)
                    dst[i] = 0xff;
                else
                    dst[i] = (0x1fe * b + s) / (s << 1);
            }
            break;
        case BLEND_MODE_ColorBurn:
            for (i = 0; i < n_chan; i++) {
                b = 0xff - backdrop[i];
                s = src[i];
                if (b == 0)
                    dst[i] = 0xff;
                else if (b >= s)
                    dst[i] = 0;
                else
                    dst[i] = 0xff - (0x1fe * b + s) / (s << 1);
            }
            break;
        case BLEND_MODE_Darken:
            for (i = 0; i < n_chan; i++) {
                b = backdrop[i];
                s = src[i];
                dst[i] = b < s ? b : s;
            }
            break;
        case BLEND_MODE_Lighten:
            for (i = 0; i < n_chan; i++) {
                b = backdrop[i];
                s = src[i];
                dst[i] = b > s ? b : s;
            }
            break;
        case BLEND_MODE_Difference:
            for (i = 0; i < n_chan; i++) {
                art_s32 tmp;

                tmp = ((art_s32) backdrop[i]) - ((art_s32) src[i]);
                dst[i] = tmp < 0 ? -tmp : tmp;
            }
            break;
        case BLEND_MODE_Exclusion:
            for (i = 0; i < n_chan; i++) {
                b = backdrop[i];
                s = src[i];
                t = ((bits32) (0xff - b)) * ((bits32) s) +
                    ((bits32) b) * ((bits32) (0xff - s));
                t += 0x80;
                t += (t >> 8);
                dst[i] = t >> 8;
            }
            break;
        case BLEND_MODE_Luminosity:
            pblend_procs->blend_luminosity(n_chan, dst, backdrop, src);
            break;
        case BLEND_MODE_Color:
            pblend_procs->blend_luminosity(n_chan, dst, src, backdrop);
            break;
        case BLEND_MODE_Saturation:
            pblend_procs->blend_saturation(n_chan, dst, backdrop, src);
            break;
        case BLEND_MODE_Hue:
            {
                byte tmp[4];

                pblend_procs->blend_luminosity(n_chan, tmp, src, backdrop);
                pblend_procs->blend_saturation(n_chan, dst, tmp, backdrop);
            }
            break;
            /* This mode requires information about the color space as
             * well as the overprint mode.  See Section 7.6.3 of
             * PDF specification */
        case BLEND_MODE_CompatibleOverprint:
            {
                gx_color_index drawn_comps = p14dev->drawn_comps;
                gx_color_index comps;
                /* If overprint mode is true and the current color space and
                 * the group color space are CMYK (or CMYK and spots), then
                 * B(cb, cs) = cs if cs is nonzero otherwise it is cb for CMYK.
                 * Spot colors are always set to cb.  The nice thing about the PDF14
                 * compositor is that it always has CMYK + spots with spots after
                 * the CMYK colorants (see gx_put_blended_image_cmykspot).
                 * that way we don't have to worry about where the process colors
                 * are.

                 * Note:  The spec claims the following:

                 If the overprint mode is 1 (nonzero overprint mode) and the
                 current color space and group color space are both DeviceCMYK,
                 then only process color components with nonzero values replace
                 the corresponding component values of the backdrop. All other
                 component values leave the existing backdrop value unchanged.
                 That is, the value of the blend function B(Cb,Cs) is the source
                 component cs for any process (DeviceCMYK) color component whose
                 (subtractive) color value is nonzero; otherwise it is the
                 backdrop component cb. For spot color components, the value is
                 always cb.

                 The equation for compositing is

                    ar*Cr = (1-as)*Cb + as*[(1-ab)*Cs+ab*B(Cb,Cs)]

                 Now if I simply set B(cb,cs) to cb for the case when the
                 DevieCMYK value (with opm true) is zero I get

                 ar*Cr = (1-as)*Cb + as*[(1-ab)*Cs+ab*Cb]

                 But what I am seeing with AR is
                    ar*Cr = (1-as)*Cb + as*[(1-ab)*Cb+ab*Cb] = (1-as)*Cb + as*Cb = Cb
                 which is what I think we want.

                 The description in the spec is confusing as it says
                "then only process color components with nonzero values replace
                 the corresponding component values of the backdrop. All other
                 component values leave the existing backdrop value unchanged"

                 which makes sense for overprinting,

                 vs.

                 "That is, the value of the blend function B(Cb,Cs) is the source
                 component cs for any process (DeviceCMYK) color component whose
                 (subtractive) color value is nonzero; otherwise it is the
                 backdrop component cb."

                 Which is NOT the same thing as leaving the backdrop unchanged
                 with the compositing equation
                 ar*Cr = (1-as)*Cb + as*[(1-ab)*Cs+ab*B(Cb,Cs)]

                 For this to work, we need to carry out the operation during
                 the mixing of the source with the blend result.  Essentially
                 replacing that mixing with the color we have here.
                 */
                if (p14dev->effective_overprint_mode && p14dev->color_info.num_components > 3
                    && !(p14dev->ctx->additive)) {
                    for (i = 0; i < 4; i++) {
                        b = backdrop[i];
                        s = src[i];
                        dst[i] = s < 0xff ? s : b; /* Subtractive zero */
                    }
                    for (i = 4; i < n_chan; i++) {
                        dst[i] = backdrop[i];
                    }
                } else {
                    /* Otherwise we have B(cb, cs)= cs if cs is specified in
                     * the current color space all other color should get cb.
                     * Essentially the standard overprint case. */
                    for (i = 0, comps = drawn_comps; i < n_chan; ++i, comps >>= 1) {
                        if ((comps & 0x1) != 0) {
                            dst[i] = src[i];
                        } else {
                            dst[i] = backdrop[i];
                        }
                    }
                }
                break;
            }
        default:
#ifndef GS_THREADSAFE
            dlprintf1("art_blend_pixel_8: blend mode %d not implemented\n",
                      blend_mode);
#endif
            memcpy(dst, src, n_chan);
            break;
    }
}