设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
楼主: 一箭烂YiJL
打印 上一主题 下一主题

[通用发布] Bitmap 类储存为 .bmp 档案(高速= =)

[复制链接]

Lv3.寻梦者

弓箭手?剑兰

梦石
0
星屑
4874
在线时间
833 小时
注册时间
2010-11-17
帖子
1140
跳转到指定楼层
1
发表于 2011-5-28 17:43:55 | 显示全部楼层 回帖奖励 |倒序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
本帖最后由 一箭烂YiJL 于 2011-5-28 17:45 编辑

0.序
这是将Bitmap 类(挺)高速的保存为bmp档案。因为之前想用柳之一的《Bitmap高速Marshal》和保存png结合,
但其实是上下倒置,而且png格式每行都要插进"0",获取每点的颜色值比起用数组"搞定"上下倒置和插"0"要快!
今天我研究了一下bmp档案,bmp格式是上下倒置,而且不用插"0",所以将拿到的数据直接写入bmp的颜色值数据流中。
然而这样比png的每点扫要快得多,VX的屏幕载图储存bmp,fps不会降!

1.脚本
脚本如下(XP/VX),柳之一的《Bitmap高速Marshal》已经不是那个样了(而且不能Marshal= =):

  1. #==============================================================================
  2. # ■ BmpWriter             by 一箭烂YiJL (获取颜色值部分 by 柳之一)
  3. #------------------------------------------------------------------------------
  4. #  使用手册:
  5. #
  6. #     BmpWriter.write(bitmap, [name[, path]])
  7. #       bitmap    : 位图
  8. #       name      : 保存文件名
  9. #       path      : 保存路径
  10. #
  11. #     自动创建路径!
  12. #==============================================================================

  13. module BmpWriter
  14.   #--------------------------------------------------------------------------
  15.   # ● 传送到内存的API函数
  16.   #--------------------------------------------------------------------------
  17.   RtlMoveMemory_pi = Win32API.new('kernel32', 'RtlMoveMemory', 'pii', 'i')
  18.   #--------------------------------------------------------------------------
  19.   # ● 制作bmp档案
  20.   #--------------------------------------------------------------------------
  21.   def self.write(bitmap, name = "Bitmap.bmp", path = "Pictures/")
  22.     ## 先要工作
  23.     Dir.mkdir(path) unless FileTest.directory?(path)
  24.     length = bitmap.width * bitmap.height
  25.     file = File.open(path + name, "wb")
  26.    
  27.     ## BitmapFileHeader
  28.     size = 54 + length * 4
  29.     chunk = "BM" + [size, 0, 54].pack("L*")
  30.     file.write(chunk)
  31.    
  32.     ## BitmapInfoHeader
  33.     chunk = [40, bitmap.width, bitmap.height, 1, 32, 0, 0, 0xEC4, 0xEC4, 256, 0].pack("L3S2L*")
  34.     file.write(chunk)
  35.    
  36.     ## Byte
  37.     data = "rgba" * bitmap.width * bitmap.height
  38.     RtlMoveMemory_pi.call(data, bitmap.address, data.length)
  39.     chunk = data
  40.     file.write(chunk)
  41.    
  42.     file.close
  43.   end
  44. end

  45. class Bitmap
  46.   #--------------------------------------------------------------------------
  47.   # ● 传送到内存的API函数
  48.   #--------------------------------------------------------------------------
  49.   RtlMoveMemory_pi = Win32API.new('kernel32', 'RtlMoveMemory', 'pii', 'i')
  50.   #--------------------------------------------------------------------------
  51.   # ● Bitmap地址
  52.   #--------------------------------------------------------------------------
  53. # [[[bitmap.object_id * 2 + 16] + 8] + 16] == 数据的开头
  54.   def address
  55.     buffer, ad = "rgba", object_id * 2 + 16
  56.     RtlMoveMemory_pi.call(buffer, ad, 4)
  57.     ad = buffer.unpack("L")[0] + 8
  58.     RtlMoveMemory_pi.call(buffer, ad, 4)
  59.     ad = buffer.unpack("L")[0] + 16
  60.     RtlMoveMemory_pi.call(buffer, ad, 4)
  61.     return buffer.unpack("L")[0]
  62.   end
  63. end
复制代码

2.范例
只有VX的: BmpWriter(VX).zip (280.85 KB, 下载次数: 248)
在任何场景按F8就可以载图,保存在 Pictures/Bitmap.bmp
没有XP的是因为XP还要找XP的Graphics.snap_to_bitmap,如果真的很想要的话就回帖伸手吧~

评分

参与人数 1星屑 +1000 收起 理由
夕阳武士 + 1000 前途无量啊你~

查看全部评分

Lv3.寻梦者

弓箭手?剑兰

梦石
0
星屑
4874
在线时间
833 小时
注册时间
2010-11-17
帖子
1140
2
 楼主| 发表于 2011-5-28 22:50:46 | 显示全部楼层
苏小脉 发表于 2011-5-28 22:33
32 位设备相关的 BMP 格式确实是这样的。扫描行倒置是和老式输出设备处理扫描线的效率有关。至于“插0”, ...

最初32位的时候我是扫点的,然后"插0",但是出现移位和颜色值错误...(加上倒置)
24位好像是没有了 a 通道。但是png是图片的每一行"插0",并不是每个颜色值。
bmp貌似是Window的位图档案。

不解柳之一用的RtlMoveMemory,虽然我知道这是将内存移来移去= =,
也知道object_id * 2就是内存位置的起始点(?),"p"所依靠的 Object#inspect 输出:
<ClassName 0x?????>  # 0x????? 正是Object#object_id * 2
所以这个和内存位置有关,但是为啥+16后函数+8函数+16函数呢?(fux2来看了...)

点评

好像在哪里说过实际的内存地址编号是左右调转的...(其实和上面的没什么关系)  发表于 2011-5-28 23:11
回复 支持 反对

使用道具 举报

Lv3.寻梦者

弓箭手?剑兰

梦石
0
星屑
4874
在线时间
833 小时
注册时间
2010-11-17
帖子
1140
3
 楼主| 发表于 2011-5-29 09:42:26 | 显示全部楼层
苏小脉 发表于 2011-5-29 01:09
32 位不用填充,3 楼已述。

然也。

谢谢~现在明白怎么能够拿到颜色值数据地址了,原来都是这些指针(和结构体的位偏移),
但为什么要让结构体里的指针指来指去?(这个出于好奇而已...)
还有为什么要 RGBQUAD 定义两个指针(first 和 last)?真奇怪
这样最后的一次RtlMoveMemory之前的偏移 16 改成偏移 12 也一样啊~

然后我根据国外分析的结构,在最后 RtlMoveMemory 之前的偏移 16 改成偏移 8 ,( BITMAPINFOHEADER 的指针)
之后拿 40 个位,就像 bmp 格式的 BitmapInfoHeader (主楼的那个)的方法来 unpack("L3S2L*"),
得出[40, Bitmap#width, Bitmap#height, 1, 32, 0, 0, 0, 0, 0, 0],(其实可以不 unpack ,写进bmp档案中)
我想苏应该知道我主楼那个的 BitmapInfoHeader 的某些值不同是无所谓的吧~

这说明了在 RM 的 Bitmap 类和 bmp 格式没什么分别的。


其实昨天本来是想研究 GIF 格式的,但网上的说明讲解不清楚,
而且有些几个关键数据弄成一个位,这个很麻烦。(又不知道那些数据有什么用)
之后想研究jpg,但jpg的延伸格式多的很...最后就研究了bmp了= =
回复 支持 反对

使用道具 举报

Lv3.寻梦者

弓箭手?剑兰

梦石
0
星屑
4874
在线时间
833 小时
注册时间
2010-11-17
帖子
1140
4
 楼主| 发表于 2011-5-29 16:29:24 | 显示全部楼层
苏小脉 发表于 2011-5-29 12:17
做面向对象编程的时候,为什么要设计这么多类,又让类的成员引用来引用去?
做面向对象编程的时候,为什么要设计这么多类,又让类的成员引用来引用去?

但我认为非 Ruby 的话,不需要这样指来指去。(Ruby 接驳的 C 就不知道了)

rgss_bminfo_t#first 是实际的像素数据的最后一行开头

可能是我不明白吧~...我只能这样说:
最后的一次 RtlMoveMemory 之前的偏移 16 和 12 得出的指针位置是一样的,
所以我认为没分别 rgss_bminfo_t#last 和 rgss_bminfo_t#first...

同时 BMP 还有自己的压缩标准,支持简单的 RLE、霍夫曼压缩,当然基本没什么实用价值。

BMP 原意似乎是不压缩。但BitmapInfoHeader中[40, w, h, 1, 32, 0, 0, ......]
(红色部分)就决定了压缩法(与否),而橙色部分就是跟压缩后大小什么的有关(没记错的话)。

点评

了解,了解,话说rgss跟api,C等连接起来,可以做很多扩展  发表于 2011-6-1 14:49
话说这些函数我都没见过。。。是ruby里的  发表于 2011-5-31 15:03
哦..哦,位图信息啊..嘿嘿,话说api没有直接复制图象到内存的方法吗?要读取二进制转存- -?  发表于 2011-5-30 09:51
bmp的文件头?,话说同格式的文件类型jpg,png,bmp文件头应该一样的把,音乐格式也是,- -bmp内存能读就ok了,不过体积是大点,当时质量也好(废话中....)  发表于 2011-5-29 21:10
回复 支持 反对

使用道具 举报

Lv3.寻梦者

弓箭手?剑兰

梦石
0
星屑
4874
在线时间
833 小时
注册时间
2010-11-17
帖子
1140
5
 楼主| 发表于 2011-5-30 18:27:57 | 显示全部楼层
苏小脉 发表于 2011-5-30 02:25
先声明一点,“引用”的概念是计算机科学中的一个通用概念,并非面向对象的语言的专利。只不过当我们在 ...
“引用”

我想 Bitmap 指针可能的其中一个原因是 Bitmap#get_pixel、set_pixel、blur......
就可以引用位图的("同一个")颜色值数据作修改、读取......

如果让 B#a 和 B#b 都变为指针,sizeof (A) 就可以是 8 字节

"sizeof (B) 就可以是 8 字节"?

而 `b.a = a;' 也仅仅是 8 个字节的拷贝而已。

8 个字节?不解...

我这里测试是不同的,不知道你那边是如何测试的。

抱歉...我傻呆呆的用了 Bitmap.new(1, 1) 来测试~

http://msdn.microsoft.com/en-us/library/dd183376(v=vs.85).aspx

然全不知道 MSDN 有记载 Bmp 格式,但是没有给 压缩方式的域 的值(数字)讲解,
但是我记得顺序是 0~5 。我之前想压缩的时候用 png 的压缩法(Zlib 的那个),
将 biSizeImage 设置为压缩后的字节的 size。(可能是测试出错或是方法错误什么的),
出来的 bmp 说是损坏档案......
回复 支持 反对

使用道具 举报

Lv3.寻梦者

弓箭手?剑兰

梦石
0
星屑
4874
在线时间
833 小时
注册时间
2010-11-17
帖子
1140
6
 楼主| 发表于 2011-5-31 16:51:18 | 显示全部楼层
苏小脉 发表于 2011-5-31 08:34
什么 Bitmap 指针?
什么 Bitmap 指针?

我有语法问题,应该是Bitmap 的那些结构体用指针指来指去。

又不是想用什么方法压缩就用什么方法压缩

我用的是 Zlib 的 DEFLATE (LZ77 + 霍夫曼) 算法,这样能够在 png 里解读。(研究 PNG 的时候发现 Zlib 还有 CRC 校验的算法)
回复 支持 反对

使用道具 举报

Lv3.寻梦者

弓箭手?剑兰

梦石
0
星屑
4874
在线时间
833 小时
注册时间
2010-11-17
帖子
1140
7
 楼主| 发表于 2011-5-31 20:14:32 | 显示全部楼层
苏小脉 发表于 2011-5-31 20:00
那这是什么意思呢?
那这是什么意思呢?

于是我想说...算了...其实我那句也应该是错的...

PNG 是另一种格式,标准自然不同。

微软那里说 BMP 可以用 PNG 的压缩法,PNG 的压缩法就是 DEFLATE ( / Gzip)....
回复 支持 反对

使用道具 举报

Lv3.寻梦者

弓箭手?剑兰

梦石
0
星屑
4874
在线时间
833 小时
注册时间
2010-11-17
帖子
1140
8
 楼主| 发表于 2011-6-2 21:40:33 | 显示全部楼层
苏小脉 发表于 2011-6-1 08:16
微软哪里说的?我查阅的材料都只提到了 RLE,霍夫曼都仅仅是存在于 OS/2 的 BMP 标准中。 ...

应该是我误会了吧~
MSDN 指出 BitmapInfoHeader 的第六个域(压缩方式)可以为 BI_PNG ,描述的译文:
表示这是一幅 PNG 图像。

于是我就用了 PNG 的压缩方式,可能是我误会其中的意思吧~
回复 支持 反对

使用道具 举报

Lv3.寻梦者

弓箭手?剑兰

梦石
0
星屑
4874
在线时间
833 小时
注册时间
2010-11-17
帖子
1140
9
 楼主| 发表于 2011-6-4 15:17:02 | 显示全部楼层
苏小脉 发表于 2011-6-3 10:52
这两个域是用在打印机硬件加速时的。

http://msdn.microsoft.com/en-us/library/dd145023(VS.85).aspx

果然是我误会了 orz ,但是这两个域为什么叫压缩方式呢?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-5-22 17:33

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表