MyException - 我的异常网
当前位置:我的异常网» Delphi » 问个关于多层图片叠加的有关问题

问个关于多层图片叠加的有关问题

www.MyException.Cn  网友分享于:2013-03-09  浏览:80次
问个关于多层图片叠加的问题
图层数目不固定,而且各个图层要有叠加顺序,
除了一张背景图(24位)外,其余各个图层均为32位的,并要在这些图层上作操作,比如在某个图层上输出文字,或是再叠加其它的小图片(PNG格式),
最关键的是,以什么方式将每个图层都以透明的方式叠加到背景图片上?
而且各个图层的操作是独立的,不会影响到其它的图层,
我现在采用的是 :将 24位 的背景图与32位的图层经过混算后达到透明,再生成一张24位的图片,然后再在paintbox上画的方法,
但是这种方法 在修改任何一个图层的图像时,都要求重新生成一次背景图,再与32位的图层进行混算,操作太麻烦,而且如果图层太多时,速度也太慢,不知哪位大侠有过类似的经验?

------解决方案--------------------
没有什么办法了。
优化下代码,再改成多线程的吧。
------解决方案--------------------
这个只能这样,多图层的显示你只能先计算混合后的效果,在输出,但是对于大图你没有必要计算全部范围,只需要计算需要显示的那部分。
------解决方案--------------------
这个就是你的优化不够了
我的imageshop也是每一个层一个类,然后输出时候计算混合结果,但是在每层都是桌面大小的情况下,5层之类还算是不怎么卡的。
------解决方案--------------------
还是说说你是怎么画透明图上去的吧,更新一张1k*1k图20ms怎么都够了,就算7、8年前的老机器40ms也足够了,小图每个时间应该更短才对

另外不知道是不是许多人觉得多线程就一定更快
多线程只在cpu有闲置的时候才起作用,在密集运算的时候除非是多核cpu且线程数不多于核数,否则只会让程序变得更慢

------解决方案--------------------
不是png么?既然都用了gdip了,那就直接用gdip一个个画出来不就完了么?
gdip除了画单个点有点儿麻烦外,剩下的操作都不比vcl的gdi封装更复杂啊

------解决方案--------------------
关于多层图形操作,不用多线程就不会很流畅,一般的做法是一个线程管一层。

上面也有人说了,多线程的总体效率未必比单一线程好,这是对的,但问题在于:单一线程影响其他操作,比如主界面更新问题(某段时间类似死机),甚至导致想切换到其他程序,都困难。

所以,用多线程不是为了时髦,也不是为了效率,而是为了更好的应用性能!
------解决方案--------------------
你的bmp不是作为背景图层么?它透明不透明没意义啊
刚才试了一下,在我的 AMD Athlon 64 2800+(05年配的)机器上,在TImage上画一个1280*1024的图片,把一个240*200的带alpha通道的png图片随机画10次,都是在100ms内完成的。对于用户体验来说,100ms基本上不会造成显著的延迟感
Delphi(Pascal) code

  tm  := GetTickCount; { tm: DWORD }
  Image1.Canvas.Draw(0, 0, bmp); { bmp: TBitmap; PixelFormat=pf24bit, Width=1280, Height=1024 前面已经准备好了 }
  g := TGPGraphics.Create(Image1.Canvas.Handle); { g: TGPGraphics; Image1: TImage; Width=1280, Height=1024 }
  for i:=1 to 10 do
  with Image1 do
    g.DrawImage(gp, Random(Width), Random(Height)); { gp: TGPBitmap 装入一张240*200的png图片,前面已经准备好了 }
  Caption := IntToStr(GetTickCount - tm);

------解决方案--------------------
楼上的,多图层混合一般请情况下不能用DrawImage函数的,因为每个图层可能带有不同的属性,比如某个层的整体透明度是40%,他的混合方式是屏幕,这些都不是DrawImage所能完成的,都只有通过自己的计算才能得到最终的结果。
------解决方案--------------------
思路有问题,不应该与背景混算透明叠加,
直接用GDI+的DrawImage方法画到有背景图的PaintBox上就行了,
只需要记住每个图层的坐标
------解决方案--------------------
1: layer里的小图片不能用单纯擦除技术而要全部重绘?
2: 小图片是不规则的且每次帖上layer时都要和layer原图作透明运算?
3: 小图片是动态生成的,而不是load文件load出来的?
4: 所有的一切都要实时计算,而不能预先存为文件,用空间换时间?


按你所说,其实你只要解决了小图贴上那两个layer的速度,你就可以解决你的问题了?
------解决方案--------------------
下面给一个32位图片合成代码,应先调用InitSysthesisAplhaMask,一次性的,不必每次调用,最后还应GlobalFreePtr(SysthesisAplhaMask)释放它。
注意:我这段代码是从一个类方法改的,没作测试。如果图层一样大,且没有局部合成,TImageData里的Offset可以不用,如果你要合成24位和32位,得修改。

Delphi(Pascal) code

  TImageData = packed record
    Width: Integer;         // 图像宽度
    Height: Integer;        // 图像高度
    Stride: Integer;        // 图像扫描线字节长度
    Offset: Integer;        // 扫描线偏移量
    Scan0: Pointer;         // 图像数据地址
  end;

var
  SysthesisAplhaMask: Pointer;

procedure InitSysthesisAplhaMask;
begin
  SysthesisAplhaMask := GlobalAllocPtr(GMEM_MOVEABLE, 256 * 2 * 8);
  asm
    push      esi

    pcmpeqb   mm7, mm7
    psrlw     mm7, 8          // mm7 = 00 ff 00 ff 00 ff 00 ff
    mov       esi, SysthesisAplhaMask
    xor       ecx, ecx
  @SumLoop:
    mov       eax, ecx
    shl       eax, 16
    or        eax, ecx
    movd      mm0, eax
    punpcklwd mm0, mm0        // mm0 = 00 sA 00 sA 00 sA 00 sA
    movq      [esi], mm0
    movq      mm1, mm7        // mm1 = 00 ff 00 ff 00 ff 00 ff
    pxor      mm1, mm0        // mm1 = 00 dA 00 dA 00 dA 00 dA
    movq      [esi + 8], mm1
    add       esi, 16
    inc       ecx
    cmp       ecx, 256
    jl        @SumLoop
    emms

    pop       esi
  end;
end;

procedure PixelSysthesis(Dest, Source: TImageData);
var
  srcOffset, dstOffset, Width: LongWord;
asm
    push      esi
    push      edi
    push      ebx

    mov       esi, [edx].TImageOperate.Scan0
    mov       edi, [eax].TImageOperate.Scan0
    mov       ecx, [edx].TImageOperate.Width
    mov       ebx, [edx].TImageOperate.Offset
    mov       eax, [eax].TImageOperate.Offset
    mov       edx, [edx].TImageOperate.Height
    mov       Width, ecx
    test      ecx, 1
    jz        @@1
    add       ebx, 4
    add       eax, 4
    jz        @@1
  @@1:
    pxor      mm7, mm7        // mm7 = 00 00 00 00 00 00 00 00
    pcmpeqb   mm6, mm6
    psrlw     mm6, 8          // mm6 = 00 ff 00 ff 00 ff 00 ff
    mov       srcOffset, ebx
    mov       dstOffset, eax
    mov       ebx, SysthesisAplhaMask
    shr       ecx, 1          // 每次合成2个像素
    cld
  @yLoop:
    push      ecx
  @xLoop:
    Dec       ecx
    js        @@3
    movq      mm0, [esi]      // mm0 = As1 Rs1 Gs1 Bs1 As0 Rs0 Gs0 Bs0
    movq      mm2, [edi]      // mm1 = Ad1 Rd1 Gd1 Bd1 Ad0 Rd0 Gd0 Bd0
    movq      mm1, mm0
    movq      mm3, mm2
    punpcklbw mm0, mm7        // mm0 = 00 As0 00 Rs0 00 Gs0 00 Bs0
    punpcklbw mm2, mm7        // mm2 = 00 Ad0 00 Rd0 00 Gd0 00 Bd0
    punpckhbw mm1, mm7        // mm1 = 00 As1 00 Rs1 00 Gs1 00 Bs1
    punpckhbw mm3, mm7        // mm3 = 00 Ad1 00 Rd1 00 Gd1 00 Bd1
    movzx     eax, [esi + 3]
    shl       eax, 4
    pmullw    mm0, [ebx + eax]    // mm0 = As0*sA Rs0*sA Gs0*sA Bs0*sA
    pmullw    mm2, [ebx + eax + 8]// mm2 = Ad0*dA Rd0*dA Gd0*dA Bd0*dA
    movzx     eax, [esi + 7]
    shl       eax, 4
    pmullw    mm1, [ebx + eax]    // mm1 = As1*sA Rs1*sA Gs1*sA Bs1*sA
    pmullw    mm3, [ebx + eax + 8]// mm3 = Ad1*dA Rd1*dA Gd1*dA Bd1*dA
    paddw     mm0, mm2        // mm0 = 00 An0 00 Rn0 00 Gn0 00 Bn0
    paddw     mm1, mm3        // mm1 = 00 An1 00 Rn1 00 Gn1 00 Bn1
    paddw     mm0, mm6        // mm0 = An0+ff Rn0+ff Gn0+ff Bn0+ff
    paddw     mm1, mm6        // mm1 = An1+ff Rn0+ff Gn0+ff Bn0+ff
    psrlw     mm0, 8          // mm0 = An0/256 Rn0/256 Gn0/256 Bn0/256
    psrlw     mm1, 8          // mm0 = An1/256 Rn1/256 Gn1/256 Bn1/256
    packuswb  mm0, mm1        // mm0 = An1 Rn1 Gn1 Bn1 An0 Rn0 Gn0 Bn0
    movq      [edi], mm0
    add       esi, 8
    add       edi, 8
    jmp       @xLoop
  @@3:
    test      Width, 1
    jz        @@2
    movzx     eax, [esi + 3]
    shl       eax, 4
    movd      mm0, [esi]      // mm0 = 00 00 00 00 As Rs Gs Bs
    movd      mm1, [edi]      // mm1 = 00 00 00 00 Ad Rd Gd Bd
    punpcklbw mm0, mm7        // mm0 = 00 As 00 Rs 00 Gs 00 Bs
    punpcklbw mm1, mm7        // mm1 = 00 Ad 00 Rd 00 Gd 00 Bd
    pmullw    mm0, [ebx + eax]    // mm0 = As*sA Rs*sA Gs*sA Bs*sA
    pmullw    mm1, [ebx + eax + 8]// mm1 = Ad*dA Rd*dA Gd*dA Bd*dA
    paddw     mm0, mm1        // mm0 = 00 An 00 Rn 00 Gn 00 Bn
    paddw     mm0, mm6        // mm0 = An+ff Rn+ff Gn+ff Bn+ff
    psrlw     mm0, 8          // mm0 = An/256 Rn/256 Gn/256 Bn/256
    packuswb  mm0, mm0        // mm0 = 00 00 00 00 An Rn Gn Bn
    movd      [edi], mm0
  @@2:
    add       esi, srcOffset
    add       edi, dstOffset
    pop       ecx
    dec       edx
    jnz       @yLoop
    emms

    pop       ebx
    pop       edi
    pop       esi
end;

文章评论

程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
程序员应该关注的一些事儿
程序员应该关注的一些事儿
总结2014中国互联网十大段子
总结2014中国互联网十大段子
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
如何成为一名黑客
如何成为一名黑客
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
程序员都该阅读的书
程序员都该阅读的书
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
老程序员的下场
老程序员的下场
编程语言是女人
编程语言是女人
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
漫画:程序员的工作
漫画:程序员的工作
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
中美印日四国程序员比较
中美印日四国程序员比较
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
我是如何打败拖延症的
我是如何打败拖延症的
鲜为人知的编程真相
鲜为人知的编程真相
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
每天工作4小时的程序员
每天工作4小时的程序员
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
为什么程序员都是夜猫子
为什么程序员都是夜猫子
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
程序员和编码员之间的区别
程序员和编码员之间的区别
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
Java程序员必看电影
Java程序员必看电影
我的丈夫是个程序员
我的丈夫是个程序员
代码女神横空出世
代码女神横空出世
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
程序员必看的十大电影
程序员必看的十大电影
 程序员的样子
程序员的样子
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
10个调试和排错的小建议
10个调试和排错的小建议
程序员的鄙视链
程序员的鄙视链
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有