3
\$\begingroup\$

I'm trying to render text to a BitmapRenderTarget, cleared with transparent color.

My TextBox is drawn on its own SharpDX.Direct2D1.BitmapRenderTarget, which I create in this way:

var bitmapRenderTarget = new SharpDX.Direct2D1.BitmapRenderTarget(renderTarget,
    SharpDX.Direct2D1.CompatibleRenderTargetOptions.None, null, null, null);

As you can see, I don't change the pixel format of BitmapRenderTarget. The pixel format of underlying SharpDX.Direct2D1.RenderTarget, on which I draw my TextBox through DrawBitmap method, is defined in the following code:

renderTargetProperties = new SharpDX.Direct2D1.RenderTargetProperties()
{
    PixelFormat = new SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.Unknown,
    SharpDX.Direct2D1.AlphaMode.Premultiplied)
};

Here is the code, that produces visual results:

// In the case 1: opaque white background
bitmapRenderTarget.Clear(SharpDX.Color.White);
...

// In the case 2: white background with 50% transparency
bitmapRenderTarget.Clear(new SharpDX.Color4(1f, 1f, 1f, 0.5f));
...

// In the case 3: fully transparent background
bitmapRenderTarget.Clear(SharpDX.Color.Transparent);
...

// The color of textBrush in all these cases is the same solid Black.
bitmapRenderTarget.DrawTextLayout(vector, textLayout, textBrush, ...);

The results:

Bad text rendering

As you can see, alpha value of the text color is somehow bound to the one in the clear color. The black line around the text is cursor, and it is drawn as it should.

How to fix this issue?

\$\endgroup\$
1
\$\begingroup\$

I'm not familiar with either SharpDX nor Direct2D.

However, my guess is that what you're seeing is caused by AlphaMode.PremultipliedAlpha.

This is the blend equation for pre-multiplied alpha:

blend(source, dest) = source.rgb + (dest.rgb * (1 - source.a))

As you can see, the alpha channel of the source is not taken into account, since the mode assumes that the color channels of the source have already been multiplied by its opacity.

In your example, source is the opaque black (r = 0, g = 0, b = 0, a = 1) text you're rendering and dest is the white background and it's (varying) opacity.

For opaque white background (r = 1, g = 1, b = 1, a = 1), you get:

source.rgb + (dest.r * (1 - source.a)) = (0,0,0) + (1,1,1) * (1-1) = (0,0,0) => black

For 50% opaque white (r = 1, g = 1, b = 1, a = 0.5) you get:

source.rgb + (dest.r * (1 - source.a)) = (0,0,0) + (1,1,1) * (1-0.5) = (0.5,0.5,0.5) => grey

And for fully translucent white (r = 1, g = 1, b = 1, a = 0) you get:

source.rgb + (dest.r * (1 - source.a)) = (0,0,0) + (1,1,1) * (1-0) = (1,1,1) => white

As you can see, it's not really 'fading' but rather 'whitening' that's happening here.

In short, I think the fix you're looking for is is to change the blend mode from PremultipliedAlpha to AlphaBlend.

Further reading: http://blogs.msdn.com/b/shawnhar/archive/2009/11/06/premultiplied-alpha.aspx

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.