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



------
图层数目不固定,而且各个图层要有叠加顺序,
除了一张背景图(24位)外,其余各个图层均为32位的,并要在这些图层上作操作,比如在某个图层上输出文字,或是再叠加其它的小图片(PNG格式),
最关键的是,以什么方式将每个图层都以透明的方式叠加到背景图片上?
而且各个图层的操作是独立的,不会影响到其它的图层,
我现在采用的是 :将 24位 的背景图与32位的图层经过混算后达到透明,再生成一张24位的图片,然后再在paintbox上画的方法,
但是这种方法 在修改任何一个图层的图像时,都要求重新生成一次背景图,再与32位的图层进行混算,操作太麻烦,而且如果图层太多时,速度也太慢,不知哪位大侠有过类似的经验?
------
没有什么办法了。
优化下代码,再改成多线程的吧。
------
这个只能这样,多图层的显示你只能先计算混合后的效果,在输出,但是对于大图你没有必要计算全部范围,只需要计算需要显示的那部分。
------
大图倒没有,都是缩略图,在最后打印时才在大图上作一次操作,生成最终输出图
目前这种操作必须用一个循环,将每一层叠加后的结果作为一张24位的输出图,再与下次要叠加的32位位图进行透明混算,操作太多了,有点吃不消,反应比较慢
------
这个就是你的优化不够了
我的imageshop也是每一个层一个类,然后输出时候计算混合结果,但是在每层都是桌面大小的情况下,5层之类还算是不怎么卡的。
------
目前我只叠了五个层,但是其中有两个层上,画了N多个小图片,几乎是整个层上都铺满了,所以任何一次的改动,都必须重画所有的层,包括层内的所有操作。。。实在想不出有什么办法能再优化了,
我用的方法是这样的
新建一个层:
var Image : TGpBitmap;  
  Gd : TGpGraphics;
begin
  Image := TGpBitmap.Craete(dW,dH , pf32bppARGB);
  Gd := TGpGraphics.Create(Image);
  //画图,文字输出,画笔添加等等其它操作
  .
  .
  .
  FSrcBmp.Handle := Image.GetHBITMAP(0);
  FsrcBmp.PixelFormat := pf32bit;
  Image.Free;
  Gd.Free; 
end;

然后再用 FSrcBmp 跟其它的24位位图合成。。。
不知楼上大侠还有没有更方便些的方法?
------
还是说说你是怎么画透明图上去的吧,更新一张1k*1k图20ms怎么都够了,就算7、8年前的老机器40ms也足够了,小图每个时间应该更短才对

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

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

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

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

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

所以,用多线程不是为了时髦,也不是为了效率,而是为了更好的应用性能!
------
楼上的,多图层混合一般请情况下不能用DrawImage函数的,因为每个图层可能带有不同的属性,比如某个层的整体透明度是40%,他的混合方式是屏幕,这些都不是DrawImage所能完成的,都只有通过自己的计算才能得到最终的结果。
------
1.你的bmp不是作为背景图层么?它透明不透明没意义啊 
背景图是24位的位图,没有透明,其它层都是32位的,目的是将各个层都跟背景图进行混算将各个层变成透明,实现多层的叠加
2.主要耗时是在各个图层的操作上,比如像我上面所说的 其中有两个层上,画了N多个小图片,几乎是整个层上都铺满了,这里是用
drawimage的方式画到 tgpbitmap 上,然后再 
  FSrcBmp.Handle := Image.GetHBITMAP(0); 
  FsrcBmp.PixelFormat := pf32bit; 
这样获取得这张32位的位图,再将这张图与背景混算透明叠加

现在只叠了两层,反复操作第二层,在上面叠加小图片时(有可能达到几百个小图片,PNG格式的),发现很耗时,
------
至于多线程,应该用不上,每个图层的操作都是独立的,而且最后要以循环的方式将每一层都进行混算叠加显示
------
思路有问题,不应该与背景混算透明叠加,
直接用GDI+的DrawImage方法画到有背景图的PaintBox上就行了,
只需要记住每个图层的坐标
------
到底有没有像11楼说的那种复杂操作?
没有的话只能说你的代码有许多多余的操作,单纯画的话,虽然gdi+好像不切换到内核态或者使用mmx单元操作,但也不会慢到哪去

------
http://blog.csdn.net/laviewpbt/archive/2009/05/02/4143881.aspx
------
楼上正解 谢谢
------
引用 14 楼 xzhifei 的回复:
思路有问题,不应该与背景混算透明叠加,
直接用GDI+的DrawImage方法画到有背景图的PaintBox上就行了,
只需要记住每个图层的坐标

------
没人来看看么?

------
全透明吗?用路径
------
我现在不明白楼主的意思了,楼主做得和PS的层有多大的区别啊?PS用了多线程而且图像还是分块处理的。

------
学习
学习 学习
------
引用 21 楼 laviewpbt 的回复:
我现在不明白楼主的意思了,楼主做得和PS的层有多大的区别啊?PS用了多线程而且图像还是分块处理的。

------
kankankan
------
完全没看懂,我面壁去了~~~
------
看到晕头转向..

假设你有5个层+1个背景,实际上是6幅图..其中两幅贴满小的图片..
bmp_bg;
bmp_layer[5];
然后假设往bmp_layer[0]/bmp_layer[1]帖满小图,再混合所有.

那么,是否bmp_layer[0]/bmp_layer[1]每次都需要全部重新全部贴上所有不同的小图呢?
不用layer直接往bg上透明BitBlt不行么?
------
我觉得楼上有人说的: 因为贴图会覆盖, 所以只需更新覆盖区域
------
to : lambochan
正如你所说,
那么,是否bmp_layer[0]/bmp_layer[1]每次都需要全部重新全部贴上所有不同的小图呢? 

这两个层的重画,是在需要时,不是每次都要
其实耗时的是在这两个层上的小图重画(比如对小图的撤消,撤消是将操作记录清除最后一步,然后再在原始图上画上所有的小图片(耗时就在这里)),每个层的透明叠加,不会很耗时

------
1: layer里的小图片不能用单纯擦除技术而要全部重绘?
2: 小图片是不规则的且每次帖上layer时都要和layer原图作透明运算?
3: 小图片是动态生成的,而不是load文件load出来的?
4: 所有的一切都要实时计算,而不能预先存为文件,用空间换时间?


按你所说,其实你只要解决了小图贴上那两个layer的速度,你就可以解决你的问题了?
------
照计单纯bitblt几百张小图片应该不会很慢的啊?
偶把GB2312整个编码汉字BltBlt()一遍(TextOut()到16x16的小图片,BitBlt()到一幅大图上,总计BitBlt()了6千多次),都很快呢..当然,是连写字一起算.
------
haihaole
------
我想楼主可能钻牛角尖了,应该换个思维方式,才能明白以上各位的方案。
要把分层处理图片和将处理过程显示出来区分开来。
先说图片分层:首先要明确图层只是个虚拟平台,层的多少,可根据需要确定,既然你觉得将很多小图片或者文字绘制到一个图层上很耗时,为什么不直接把每个小图片作为一个单独的图层处理,而非要实现绘制到一个图层上?你可能考虑到小图片尺寸,可以确定一个类或者记录作为虚拟图层层面,大小一样,记录下小图片的坐标,就是一个独立的图层了。如此一来,在拼合之前,每个图层可灵活组装、添加和拆卸,根本就不耗时。
再说显示处理过程,其实每个过程的显示都相当于一次图层拼合,这可能就是你所说的耗时,我已经给你说过了,这是没办法的事,显示器是物理的,没法“分层”,每次都得从头开始绘制,连操作系统本身都是这么干的。当然,如何快速的显示应该讲究,GDI+的DrawImage过程是很慢的,不建议使用;TBitmap不能很好的显示透明图片,所以也不合适,剩下来只有2种方法:一是使用Windows API,二是自己合成到屏幕画布上,我建议你在后台拼合好图层,一次性刷新到屏幕(相当于使用双缓冲)。
我上次给你的24位与32位图片合成方法可用于图层的拼合,那种方法是比较快的(我指的是“方法算法”,但是我给你的过程中含除法会影响速度,可改为:((Spurce Alpha * Source RGB) + (256 - Source Alpha) * Dest RGB) + 255) shr 8),如果图层比显示窗口大很多,应作局部图层合成,以提高速度。如此还嫌速度慢,只能用ASM、MMX等进一步优化了。
------
楼上的和我讲得意思差不多,一个层一个类,每个类中都记录了层的位置坐标以及其他的诸如透明混合方式等信息,显示的时候 也只能从第一个层计算到最后一个层得到混合后的显示数据,然后再把这个显示数据一次性绘制到你的目标DC上。
我的博客上写的很清楚啊

这个计算是没有办法的事。
------
呵呵,没改彻底,代码中的[xxx].TImageOperate.xxxx改为[xxx].TImageData.xxxx
------
学习
------
汇编的牛人

以前帮人弄过一个类似的,不过是两个图片合成,多个图片应该也差不多
楼主可以到下面的帖子看看
http://topic.csdn.net/u/20090305/11/de000540-4968-4152-afc0-779ffac4938b.html
------
想了半天,与其给你一大堆理论建议,不如直接推荐一个支持图层和Alpha通道的库:P:http://graphics32.org
------
应该针对非mmx、mmx、sse写不同的代码,现在主流cpu都至少支持sse,128bits的xmm寄存器操作起来比64bits的mmx寄存器效率更高

------
引用 29 楼 lambochan 的回复:
1: layer里的小图片不能用单纯擦除技术而要全部重绘?
2: 小图片是不规则的且每次帖上layer时都要和layer原图作透明运算?
3: 小图片是动态生成的,而不是load文件load出来的?
4: 所有的一切都要实时计算,而不能预先存为文件,用空间换时间?


按你所说,其实你只要解决了小图贴上那两个layer的速度,你就可以解决你的问题了?

------
mark
------
都是些牛人,太羡慕你们了
------
LZ在做Game? 屏幕上有几百个不停地动来动去的"精灵" ?
------
引用 43 楼 lambochan 的回复:
LZ在做Game? 屏幕上有几百个不停地动来动去的"精灵" ?

------
例如要擦除某个元素,只需要往该区域矩形把原来的BG图该区域帖回去不就擦除了? 
:
这些小图片有可能在某个位置上是重叠,也就是说,清除了这个,它下面一层还有一个,或是多个,取混合输出图的背景覆盖的方法应该不行
------
恩 不错值得考虑
------
引用 46 楼 mdejtod 的回复:
例如要擦除某个元素,只需要往该区域矩形把原来的BG图该区域帖回去不就擦除了?
:
这些小图片有可能在某个位置上是重叠,也就是说,清除了这个,它下面一层还有一个,或是多个,取混合输出图的背景覆盖的方法应该不行

------
up
------
hao
------
不懂

------
UP...
------
操作图层时,应该只需要处理某个区域内的数据,而不需要处理所有的区域,这样速度会快很多
------
引用 53 楼 xzhifei 的回复:
操作图层时,应该只需要处理某个区域内的数据,而不需要处理所有的区域,这样速度会快很多

------

------
学一学
------
以前我以为考上大学就可以幸福了,后来发现我找不到工作;
后来我以为找到工作就可以幸福了,后来我发现delphi要掌握很多东西;
再后来我以为掌握了delphi就可以开始幸福了,后来发现我还不懂很多重要的技术;
再以后我以为有了技术就可以幸福了,后来发现我还是错了;
不过我还是搞懂一点:幸福不需要技术,在中国尤其如此。
------
貌似看懂 呵呵 要是我每个小图遍历一个方法,设置初始值和变量,然后处理小图的时候调用一个方法!速度应该还可以吧
桂ICP备07017180号