[Bug] GDI+ 渐变填充出错,在起始位置出现额外线条
2010-01-20 21:29
99 查看
最近被这个问题搞的我很无语,不多说,直接贴代码了:
测试函数:
出来的效果如下(运行环境 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?
测试函数:
调用: #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?
相关文章推荐
- [Bug] GDI+ 渐变填充出错,在起始位置出现额外线条
- Anthem Bug:当页面同时出现Anthem.FileUpload和TextArea时callback出错(BADRESPONSE)
- 使用Json.NET出现“文档的顶层无效。处理资源 URl 时出错。第 1 行,位置: 1
- 滑动布局嵌套,导致跳转到起始位置时出现的滑动问题
- 找出A字符串中出现B字符串的起始位置
- AndroidSdk开发,混淆后的代码出现bug后怎么找到bug位置
- ie9 scrollbar bug(IE9父容器overflow:auto时,子容器状态更改导致滚动条下出现额外空间)
- Graphics类创建渐变线条和填充的方法
- 正则表达式的字符组取反(负值字符集合/范围)^必须出现在起始位置
- 创建渐变线条和填充
- 解决vc++DEBUG ERROR问题前几天师弟调试程序的时候出现了这样一个错误,出错的位置是在delete [] 一个动态分配的数组时出现的。 经过调查发现错误是因为他之前在给数组赋值的时候越界了
- 友盟统计和dsym定位iOS出现bug的位置
- 分页起始位置的懒汉判断方法
- 26.在一个字符串(1<=字符串长度<=10000,全部由大写字母组成)中找到第一个只出现一次的字符,并返回它的位置
- vitamio videoView 用隐藏除videoview的控件,并旋转屏幕方向实现的全屏功能,出现的画面不能填充满videoview(画面不完整)
- 《剑指offer》-第一个只出现一次的字符位置
- Qt学习之路(27): 渐变填充
- jQuery 全选与反选时出现的bug!
- vs 2005 与matalab混编出错解决: matrix.h里面出现错误
- 计算文本的高度并显示在label上出现灰色的线条