Project1

标题: Bitmap透明转不透明 [打印本页]

作者: IamI    时间: 2009-7-24 09:52
标题: Bitmap透明转不透明
本帖最后由 IamI 于 2009-7-24 14:02 编辑

现有一Bitmap(尺寸640*480),用Get_Pixel所得结果,Alpha值全部为0(RGB是正常的),有没有什么快捷的方法使该Bitmap能够正常显示(不论任何方法均可,包括在Sprite上,Window上动手脚,但是逐点Set过慢)

问题的来源是……使用Xp的snap to bitmap(http://rpg.blue/viewthread.php?tid=111502)时若在Vista系统下,得到的Bitmap就如上所述。如能解决该问题,同认可。

认可请求追加500分。


作者: 蓝の星辰    时间: 2009-7-24 10:55
提示: 作者被禁止或删除 内容自动屏蔽
作者: ONEWateR    时间: 2009-7-24 11:59
同Ls,帮顶一下~
用set的话,也接近循环 640 * 480 次 - -~

但也发现一问题
  1. 不论任何方法均可……但是逐点Set过慢
复制代码
- -~
作者: IamI    时间: 2009-7-24 12:20
本帖最后由 IamI 于 2009-7-24 12:26 编辑

发现诡异现象,用优化2版(http://rpg.blue/viewthread.php?tid=111502),就会诡异
用神思原版(http://rpg.blue/viewthread.php?tid=111145),巨卡,但是没这个故障
同Ls,帮顶一下~
用set的话,也接近循环 640 * 480 次 - -~

但也发现一问题不论任何方法均可……但是逐点Set过慢- -~
ONEWateR 发表于 2009-7-24 11:59

不小心口误而已= =
帮顶一下
啊,现在想IamI这样NB的前辈越来越少了

ps:为什么要设置隐藏内容,看不到
蓝の星辰 发表于 2009-7-24 10:55

db你不是问过Graphics.snap_to_bitmap这个问题了= =
作者: 紫苏    时间: 2009-7-24 12:29
本帖最后由 紫苏 于 2009-7-24 12:30 编辑

我也是 Vista 系统,但没有这个问题 O.o
snap_to_bitmap 的时候强制改变 alpha 值试试?
  1. def snap_to_bitmap
  2.   width, height = 640, 480
  3.   hb = Bitmap.new(width, height)
  4.   rgbs = self.bitmap_data
  5.   len = width * 4  
  6.   for y in 0...height
  7.     break if 2 * y >= height - 1
  8.     nth1 = y * len
  9.     nth2 = (height - 1 - y) * len
  10.     tStr = rgbs[nth1,len]
  11.     rgbs[nth1, len] = rgbs[nth2, len]
  12.     rgbs[nth2, len] = tStr

  13.     i = 3
  14.     while i < len
  15.       rgbs[nth1 + i] = 0xFF
  16.       rgbs[nth2 + i] = 0xFF
  17.       i += 4
  18.     end

  19.   end
  20.   RtlMoveMemory.call(hb.address, rgbs, 640 * 480 << 2)
  21.   return hb
  22. end
复制代码

作者: IamI    时间: 2009-7-24 12:34
我也是 Vista 系统,但没有这个问题 O.o
snap_to_bitmap 的时候强制改变 alpha 值试试?def snap_to_bitmap
  width, height = 640, 480
  hb = Bitmap.new(width, height)
  rgbs = self.bitmap_data
  len = width ...
紫苏 发表于 2009-7-24 12:29

成功。去认证了。(350分)
剩下150分用来悬赏谁告诉我为什么。我的版本是snap to Bitmap优化2版,
电脑是Vista SP1
作者: dbshy    时间: 2009-7-24 12:47
╮(╯▽╰)╭
API知识不足,当初这个脚本一直没看懂,LS哪位前辈来解释一下此脚本

PS:IAMI前辈用这个东东干嘛( ⊙o⊙?)
作者: IamI    时间: 2009-7-24 12:49
╮(╯▽╰)╭
API知识不足,当初这个脚本一直没看懂,LS哪位前辈来解释一下此脚本

PS:IAMI前辈用这个东东干嘛( ⊙o⊙?)
dbshy 发表于 2009-7-24 12:47

精灵说原来的截图存档有Bug,于是某苦工去写一个新的
同,能够解释该脚本亦认证剩下的150分
作者: 紫苏    时间: 2009-7-24 13:34
本帖最后由 紫苏 于 2009-7-24 13:56 编辑

原来的 bitmap_data 方法写得乱七八糟的,我给改了一下,试试看还有没有问题?
  1. class << Graphics
  2.   GetDC = Win32API.new("user32", "GetDC", 'L', 'L')
  3.   CreateCompatibleBitmap = Win32API.new("gdi32", "CreateCompatibleBitmap", "lll", "l")
  4.   CreateCompatibleDC = Win32API.new("gdi32", "CreateCompatibleDC", "l", "l")
  5.   SelectObject = Win32API.new("gdi32", "SelectObject", "ll", "l")
  6.   BitBlt = Win32API.new("gdi32", "BitBlt", "lllllllll", "l")
  7.   GetBitmapBits = Win32API.new("gdi32", "GetBitmapBits", "llp", "l")
  8.   ReleaseDC = Win32API.new("user32", "ReleaseDC", "LL", 'L')
  9.   DeleteDC = Win32API.new("gdi32", "DeleteDC", "l", "l")
  10.   DeleteObject = Win32API.new("gdi32", "DeleteObject", "l", "l")
  11.   SRCCOPY = 0xCC0020
  12.   RtlMoveMemory = Win32API.new('kernel32', 'RtlMoveMemory', 'ipi', 'i')
  13.   HWnd = Win32API.new("user32", "GetActiveWindow", nil, 'l').call
  14.   DwCount = 640 * 480 * 4
  15.   @@lpBits = "\000" * DwCount
  16.   #--------------------------------------------------------------------------
  17.   # ● snap_to_bitmap
  18.   # 将当前画面转换为Bitmap对象
  19.   #--------------------------------------------------------------------------
  20.   def snap_to_bitmap
  21.     width, height = 640, 480
  22.     hb = Bitmap.new(width, height)
  23.     rgbs = self.bitmap_data
  24.     len = width * 4  
  25.     for y in 0...height
  26.       break if 2 * y >= height - 1
  27.       nth1 = y * len
  28.       nth2 = (height - 1 - y) * len
  29.       tStr = rgbs[nth1,len]
  30.       rgbs[nth1, len] = rgbs[nth2, len]
  31.       rgbs[nth2, len] = tStr
  32.     end
  33.     RtlMoveMemory.call(hb.address, rgbs, 640 * 480 << 2)
  34.     return hb
  35.   end
  36.   #--------------------------------------------------------------------------
  37.   # ● bitmap_data
  38.   # 获取当前画面的数据部分```
  39.   # RGB依然是调转过来了`= =``
  40.   #--------------------------------------------------------------------------
  41.   def bitmap_data
  42.     hScrDC = GetDC.call(HWnd)
  43.     hMemDC = CreateCompatibleDC.call(hScrDC)
  44.     hBitmap = CreateCompatibleBitmap.call(hScrDC, 640, 480)
  45.     SelectObject.call(hMemDC, hBitmap)
  46.     BitBlt.call(hMemDC, 0, 0, 640, 480, hScrDC, 0, 0, SRCCOPY)
  47.     GetBitmapBits.call(hBitmap, DwCount, @@lpBits)
  48.     DeleteObject.call(hBitmap)
  49.     DeleteDC.call(hMemDC)
  50.     ReleaseDC.call(HWnd, hScrDC)
  51.     return @@lpBits
  52.   end
  53. end
复制代码
原来的 bitmap_data 很诡异地去创建了一个屏幕 DC,然后通过诡异的超大内存(那个宽 640 * 2,高 480 * 2 的地方实在莫名其妙) DC 把屏幕 DC 的 RM 窗口客户区矩形位图复制了过去,实际上截取窗口客户区根本不需要这么麻烦——
直接用 GetDC 获取客户区 DC,然后通过 CreateCompatibleDC 和
CreateCompatibleBitmap 创建兼容 DC 和兼容位图,也就是创建了一个绘图的缓存(绘图缓存在游戏中是必不可少的,所有的绘制先要在缓存中完成,然后再一举拷贝到客户区 DC 上,这就是所谓的双缓存技术),然后把客户区的位图拷贝到这个缓存中,最后通过 GetBitmapBits 就获取到了位图的数据(宽*高*4 的数组,4是因为在内存中一个像素占四个字节,即 BGRA 四个通道)

位图的数据有了,接下来就是要想办法把数据转换成 RM 的 Bitmap 对象~Bitmap 的 address 方法就是通过 [[[Bitmap#object_id * 2 + 16] + 8] + 16] 的算法获取了 Bitmap 对象的内存首地址(详见柳之一的 Bitmap 序列化贴),这样我们就可以直接修改对象的内存了

最后是 Graphics.snap_to_bitmap 方法,它首先创建了一个 Bitmap 对象,然后截图并获取了窗口快照的数据~由于位图的像素数据是按照从下到上,从左到右的顺序排列的,而 RM 的 Bitmap 对象却是从上到下,从左到右,所以这两者的扫描行位置是相反的,位图数据的第一行其实应该是 Bitmap 对象的最后一行,位图数据的第二行应该是 Bitmap 对象的倒数第二行,以此类推~所以 snap_to_bitmap 就做了相应的行交换,交换完毕之后把数据拷贝到对象所在的内存地址,这样一来我们需要的 Bitmap 对象就创建成功了
作者: IamI    时间: 2009-7-24 13:40
原来的 bitmap_data 方法写得乱七八糟的,我给改了一下,试试看还有没有问题?class = height - 1
      nth1 = y * len
      nth2 = (height - 1 - y) * len
      tStr = rgbs[nth1,len]
      rgbs[nth1, len] = ...
紫苏 发表于 2009-7-24 13:34

俄……俄……俄……哪里来的Bitmap_Data= =
这不就是优化二版吗0 0
作者: dbshy    时间: 2009-7-24 14:58
听了紫苏大的解释,在下MS明白了
啊,感叹一下,隔行如隔山




欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1