问个关于多层图片叠加的问题
图层数目不固定,而且各个图层要有叠加顺序,
除了一张背景图(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 esiend;
[解决办法]
想了半天,与其给你一大堆理论建议,不如直接推荐一个支持图层和Alpha通道的库:P:http://graphics32.org
[解决办法]
哦,那用简单擦除ms就可以不用全部重新往BG上计算帖图啊.
例如要擦除某个元素,只需要往该区域矩形把原来的BG图该区域帖回去不就擦除了?
而假如还有元素在上面覆盖着,那也只需要计算该区域的合成运算而不用整个图重来啊?
[解决办法]
操作图层时,应该只需要处理某个区域内的数据,而不需要处理所有的区域,这样速度会快很多