| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1729 人关注过本帖
标题:进阶《窗体透明示例三》如何用GDI实现透明、背景动画或换肤的效果
只看楼主 加入收藏
GoldenSpider
Rank: 2
等 级:论坛游民
威 望:3
帖 子:17
专家分:77
注 册:2010-5-15
收藏
 问题点数:0 回复次数:10 
进阶《窗体透明示例三》如何用GDI实现透明、背景动画或换肤的效果
为简化只做了窗体的顶部比较复杂的一块,白云飘飘、淡入淡出效果截图:
图片附件: 游客没有浏览图片的权限,请 登录注册

执行文件:
Gs-AlphaWIn.zip (178.42 KB)


虽然说,采用wpf可以很轻松的实现一些特效,可一来需要.net,二是c#,三是vista以上...这些限制让汇编爱好者“屡试不爽”。
以下是前段时间写的小东西的体会,小结一些,可能表述不甚好或笔误,有不明白或有更好的想法可以分享交流一下。

1. 如何实现窗体透明,控件不透明
为了更加轻松地做到这一点,DIB位图采用RGBA的32位带alpha通道的真彩位图(也由RGBA的png转成dib32),如果是自绘控件的话,可以这块全不透明即可alpha=0xff。
"Try the above procedure. Create your bitmap and make sure the part where the webbrowser control should appear is not transparent;"

参考: https://bbs.bccn.net/viewthread.php?tid=359762&page=1#pid2332590
关键点:
  (1).CreateWindowEx中使用WS_EX_LAYERED 图层窗体类型
  (2).窗体更新使用UpdateLayeredWindow
程序代码:
  BOOL WINAPI UpdateLayeredWindow(
    _In_      HWND hwnd,
    _In_opt_  HDC hdcDst,
    _In_opt_  POINT *pptDst,
    _In_opt_  SIZE *psize,
    _In_opt_  HDC hdcSrc,
    _In_opt_  POINT *pptSrc,
    _In_      COLORREF crKey,
    _In_opt_  BLENDFUNCTION *pblend,
    _In_      DWORD dwFlags
  );

  最后一个参数dwFlags选择ULW_ALPHA,而参数pblend比较关键,它是一个已初始化赋值了的BLENDFUNCTION结构的指针
程序代码:
  typedef struct _BLENDFUNCTION
  {
      BYTE     BlendOp;
      BYTE     BlendFlags;
      BYTE     SourceConstantAlpha;
      BYTE     AlphaFormat;
  }BLENDFUNCTION, *PBLENDFUNCTION, *LPBLENDFUNCTION;

  这里,我们初始化为:
  pblend       BLENDFUNCTION   AC_SRC_OVER,0,255,AC_SRC_ALPHA
  也即,使用DIB32中的alpha进行混合运算(实质是加权平均),公式如下(见msdn):
  If the source bitmap has per-pixel alpha, the constant alpha is not used (0xff) as shown in the following table.
  Dst.Red     = Src.Red   + (1 - Src.Alpha) * Dst.Red
  Dst.Green   = Src.Green + (1 - Src.Alpha) * Dst.Green
  Dst.Blue    = Src.Blue  + (1 - Src.Alpha) * Dst.Blue
   
  If the destination bitmap has an alpha channel, then:
  Dest.alpha  = Src.Alpha + (1 - SrcAlpha) * Dst.Alpha
  
  *****还有一个决定成败的是,这里的src和dst都是预先经过预乘alpha的数据
  比如Src上的一个点为(RGBA) 为db 0x24,0x56,0xf5,0x33
  经过预乘alpha的数据为db 0x24*0x33/256,0x56*0x33/256,0xf5*0x33/256,0x33
  asm片段:
程序代码:
      xloop:
        mov eax,[esi]
        mov edx,eax
        rol eax,16
        shr edx,24 ; A
        mul dl    ; B * A
        rol eax,8
        mul dl    ; G * A
        rol eax,8
        mul dl    ; R * A
        mov al,dl
        ror eax,8
        mov [esi],eax
        add esi,4
        dec ecx
        jnz xloop

   所以,你看到的素材透明的部分偏黑,是已经经过预乘alpha处理了的,当然你也可以在载入bmp后预乘一次即可。

  (3).DIB32位图(RGBA)载入CreateDIBSection
  
程序代码:
    HBITMAP CreateDIBSection(
      HDC hdc,          // handle to device context
      CONST BITMAPINFO *pbmi,
                        // pointer to structure containing bitmap size,
                        // format, and color data
      UINT iUsage,      // color data type indicator: RGB values or
                        // palette indexes
      VOID *ppvBits,    // pointer to variable to receive a pointer to
                        // the bitmap's bit values
      HANDLE hSection,  // optional handle to a file mapping object
      DWORD dwOffset    // offset to the bitmap bit values within the
                        // file mapping object
    );
  第四个参数ppvBits,调用CreateDIBSection之后,ppvBits是一个未初始化的数据存储块的指针,
  通过memcopy等方式,将DIB32的数据拷贝进去即可,(否则可能就出现网上说的显示一片黑)。
  
  (4).对窗体的渲染都是针对ppvBits所指向的这块内存进行的,然后用UpdateLayeredWindow进行更新。
  而UpdateLayeredWindow能为我们做什么呢?它可以做的是将ppvBits所指向的这块内存与桌面位图进行alpha混合,这样
  就不需要我们来获得桌面位图,通常我们这样做的效率不高,也无法做到即时更新(拖动窗体或桌面背景不变化)。
  
2.如何实现背景动画?
  对于这个问题,在没解决之前我考虑了一整天,网上也找不到相关的东西,或许很多人以此...你懂的,一直在纠结是不是应该获取桌面位图进行混合后,再与ppvBits所指向的这块前景内存
  混合,这样就可以实现背景变动了。其实不然,UpdateLayeredWindow能为我们做的不多,如1(4)提到的。
  在看到BLENDFUNCTION后顿悟了。
  既然UpdateLayeredWindow能实现ppvBits所指向的这块内存与桌面位图进行alpha混合,为何我们不能在ppvBits所指向的这块内存之上进行alpha混合呢。
  这是关键的,答案是可行的。图层的思想体现出来了,这个层次是自行设计的,比如云朵作为一个图层A,太阳作为另一个图层B,主景再作一个层C。
  对层进行巧妙有序的安排,比如云朵可能要在太阳的上面顠,又能在主景的后面。这个在做混合(Dib32AlphaBlend)的时候,图层的混合次序可以为:
  B=AlphaBlend(B,C) -> B=AlphaBlend(B,A) -> copy(ppvBits,B) ->UpdateLayeredWindow(ppvBits)
  比如QQ聊天窗体可以如下排布:
  
图片附件: 游客没有浏览图片的权限,请 登录注册

  Dib32AlphaBlend的混合算法见1(2)中对BLENDFUNCTION的说明部分。
  对于Dib32AlphaBlend我也实现了一个效率不算高,但是有效的代码:
  说明:将pBitDst这块内存的pDstRect位置处与pBitSrc这块内存的pSrcRect处的(dwWight*dwHight)矩阵块进行alpha混合。
  有个细节要提醒一下,DIB32位图倒过来成像的,存储的第一行显示出来,也即在窗体的最底部一行,所以DibCoordinate来完成这个转换。
程序代码:
proc Dib32AlphaBlend uses esi edi, pBitDst,pDstRect,pBitSrc,pSrcRect,dwWight,dwHight
    local   dwSrcWight:DWORD,dwDstWight:DWORD
    mov     edx,[pSrcRect]
    mov     eax,[edx+RECT.right]
    shl     eax,2
    mov     [dwSrcWight],eax
    stdcall DibCoordinate,[pBitSrc],edx,[dwHight]
    mov     esi,eax
    ;---------------------------------------
    mov     edx,[pDstRect]
    mov     eax,[edx+RECT.right]
    shl     eax,2
    mov     [dwDstWight],eax
    stdcall DibCoordinate,[pBitDst],edx,[dwHight]
    mov     edi,eax
    ;---------------------------------------
.loopy:
    mov     edx,[dwWight]
    push    edi
    push    esi
.loopx:
    mov     cl,255
    sub     cl,[esi+3]
   
    mov     al,[edi]
    mul     cl          ;ax=al*cl
    add     ah,[esi]
    mov     [edi],ah
   
    mov     al,[edi+1]
    mul     cl          ;ax=al*cl
    add     ah,[esi+1]
    mov     [edi+1],ah
   
    mov     al,[edi+2]
    mul     cl          ;ax=al*cl
    add     ah,[esi+2]
    mov     [edi+2],ah
   
    mov     al,[edi+3]
    mul     cl          ;ax=al*cl
    add     ah,[esi+3]
    mov     [edi+3],ah
    add     esi,4
    add     edi,4
   
    sub     edx,1
    jnz     .loopx
    pop     esi
    pop     edi
    add     esi,[dwSrcWight]
    add     edi,[dwDstWight]
   
    sub     [dwHight],1
    jnz     .loopy
   
    ret
endp
3.如何换肤,这个更加容易,只需要更换一下A、B或C的图。
搜索更多相关主题的帖子: 执行文件 vista 爱好者 动画 如何 
2013-08-17 13:57
zklhp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:china
等 级:贵宾
威 望:254
帖 子:11485
专家分:33241
注 册:2007-7-10
收藏
得分:0 
膜拜大神 膜拜大作
2013-08-17 14:52
hu9jj
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:红土地
等 级:贵宾
威 望:400
帖 子:11771
专家分:43421
注 册:2006-5-13
收藏
得分:0 
学习

活到老,学到老!http://www.(该域名已经被ISP盗卖了)E-mail:hu-jj@
2013-08-17 21:16
wp231957
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:神界
等 级:贵宾
威 望:423
帖 子:13688
专家分:53332
注 册:2012-10-18
收藏
得分:0 
看看

DO IT YOURSELF !
2013-08-18 21:32
bingghost
Rank: 2
等 级:论坛游民
帖 子:70
专家分:85
注 册:2012-1-4
收藏
得分:0 
蜘蛛出品 必属精品

我的头像就是我的女神 可惜我的女神已经死了 所以我的心也死了
2013-09-01 13:10
Explorerlxz
Rank: 9Rank: 9Rank: 9
来 自:zzu
等 级:蜘蛛侠
威 望:4
帖 子:302
专家分:1032
注 册:2013-4-24
收藏
得分:0 
请问蜘蛛大侠:这个程序打开之后关不掉(我现在用的xp系统),怎么回事?任务管理器里也没有这个程序,难道隐藏进程了?小弟汇编不咋样,请解释一下!
请问zklhp大侠:您分析的那篇文章中的macro.asm在什么地方呀,我用的masmplus上面好像没有此项,难道以前你们在什么地方发表过?
2013-09-01 17:07
Alar30
Rank: 10Rank: 10Rank: 10
等 级:贵宾
威 望:10
帖 子:988
专家分:1627
注 册:2009-9-8
收藏
得分:0 
这个好。。
谢谢了哈
2013-09-12 11:39
Alar30
Rank: 10Rank: 10Rank: 10
等 级:贵宾
威 望:10
帖 子:988
专家分:1627
注 册:2009-9-8
收藏
得分:0 
哇哈哈
学习的来了哈。。。
2013-09-30 11:39
汇编好有用
Rank: 1
等 级:新手上路
帖 子:2
专家分:0
注 册:2013-10-14
收藏
得分:0 
这里好像是汇编区啊,怎么来这个啊
2013-10-14 08:04
汇编好有用
Rank: 1
等 级:新手上路
帖 子:2
专家分:0
注 册:2013-10-14
收藏
得分:0 
哦哦,是我错了
2013-10-14 08:21
快速回复:进阶《窗体透明示例三》如何用GDI实现透明、背景动画或换肤的效果
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.021452 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved