您的位置:首页 > 其它

[Bug] GDI+ 渐变填充出错,在起始位置出现额外线条

2010-01-20 21:29 99 查看
最近被这个问题搞的我很无语,不多说,直接贴代码了:

测试函数:

调用:

#define MWIDTH	102
#define MHEIGHT	100
void CXXXDlg::OnPaint()
{
CPaintDC dc(this);

CRect rt;
rt.left = 50;
rt.top = 50;
rt.right = rt.left + MWIDTH;
rt.bottom = rt.top + MHEIGHT;

test_gdiplus_SetBlendBellShape(dc.GetSafeHdc(), rt);
}

出来的效果如下(运行环境 VC6 + XP SP3):





放大的效果:





  可以看到有一条多余的蓝边出现在填充矩形的左侧,如果把 SetBlendBellShape 的调用注释掉则不会出现,按道理1.0就应该是等价于默认的设置,所以怀疑这是GDI+的bug



  后来在测试过程中发现即使不调用 SetBlendBellShape,填充矩形在某些 size 下也会出现这条额外的边,比如在上述code中的size 102x100,简单的说这个问题还跟填充区域的大小甚至位置有关。

  就这个问题Google了一下,找到一些references:
1) http://blog.csdn.net/mubingyun/archive/2008/12/09/3484260.aspx
2) http://www.codeproject.com/KB/GDI-plus/TurnThePage.aspx

  弄了很久后发现要解决这个问题,貌似有几个解决方法:

1、调用 Graphics::SetPixelOffsetMode( PixelOffsetModeHalf ),好像在某些case下还是不work。
2、使 brush 的矩形比填充的矩形大一个像素单位。
3、调用 LinearGradientBrush::SetWrapMode( WrapModeTileFlipXY ),实际就是重新拿第一个颜色去覆盖那条多余的蓝边。

看来GDI+作为Bleeding Edge的技术就是会让使用者承担风险啊。

1/18/2010(在发布此随笔之前),在搜索了一天后找到一些资料:

1) http://stackoverflow.com/questions/110081/lineargradientbrush-artifact-workaround
2) http://www.experts-exchange.com/Microsoft/Development/.NET/Visual_CSharp/Q_23329115.html
3) http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.languages.csharp/2007-01/msg01592.html

你会看到有人(包括一个MS MVP)说这是一个已知的bug,并且建议说把brush弄得比要填充的矩形大一点(一个像素即可)可以解决问题。

但这样是不是真的就是最佳workaround了呢?看这个发帖提问的人的回复:

I had tried inflating the brush, and it seemed to eliminate the random
line. But it introduced its own problems:

Some of the shaded areas get as narrow as 3 pixels (perspective-shrink
during animation). That means that a 1-pixel miss results in a very
visible 33% change in the outer color. This is not as ugly as the
black lines, but still a noticeable glitch.

And with the inflated brush, there's now no way to get a pure white or
pure black row of pixels on the outer edge of a 3 pixel wide object,
as the crossfade is already at 20% (1 pixel out of 5) when the brush
hits the object edge. But then the bug will pop in and randomly draw a
pure white or black edge.

主要意思是说这个方法引入了其他问题,比如对比增大brush的矩形之前,终点的颜色不太一样了,更重要的是在矩形比较小的时候这个问题还是会出现:



上面是在 位置249,249 大小为7x100的时候的截图

就我看来,LinearGradientBrush::SetWrapMode( WrapModeTileFlipXY ) 虽然有点tricky,但至少目前都还没发现问题重现,看来这暂时是个最终解决方法了。

顺便贴下某人的complaints(来源: http://weblogs.mozillazine.org/tor/archives/2005/06/):

I'm considering switching the renderer that Mozilla SVG uses on win32 to cairo from GDI+. The reasons for this:

Less problems for the user, as they don't have to deal with downloading GDI+ if they're on an older system (pre-XP).

Some bugs in GDI+ are unfixable (or at least, would take a lot of effort). For example the spread method for radial gradients, bug 296411.

Consistent behavior between platforms, up to the quality of the respective cairo backends.

Saving effort adding features for GDI+, which likely won't be used past 1.8.x. The patch for <svg:textPath>, bug 282579, is an example of this.

注意第二点,"Some bugs in GDI+ are unfixable",that is so microsoft, heh?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐