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

Project1

 找回密码
 注册会员
搜索
查看: 8049|回复: 20
打印 上一主题 下一主题

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

[复制链接]

Lv4.逐梦者

弓箭手?剑兰

梦石
0
星屑
5529
在线时间
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 前途无量啊你~

查看全部评分

Lv5.捕梦者 (管理员)

老黄鸡

梦石
0
星屑
42404
在线时间
7602 小时
注册时间
2009-7-6
帖子
13506

开拓者贵宾

2
发表于 2011-5-28 18:34:18 | 只看该作者
在手机上不能回复,在电脑上竟然还没人回复= =
能详细说一下RtlMoveMemory函数的作用吗?看了半天度娘没懂= =

点评

RtlMoveMemory就是复制内存,你去搜搜CopyMemory就知道了  发表于 2011-6-9 08:10
我发的这些"不大众化"没什么人会回帖(不多人懂用- -),或许这样只是促进"不大众化"的分享吧~~("不大众化"没啥回报= =)  发表于 2011-5-28 23:10
fux2 来看(参与) 4楼 或之后的评论吧~  发表于 2011-5-28 22:51
RGDirect - DirectX驱动的RGSS,点我了解.
RM全系列成套系统定制请联系QQ1213237796
不接受对其他插件维护的委托
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
110
在线时间
953 小时
注册时间
2007-4-25
帖子
805
3
发表于 2011-5-28 22:33:48 | 只看该作者
32 位设备相关的 BMP 格式确实是这样的。扫描行倒置是和老式输出设备处理扫描线的效率有关。至于“插0”,那是提高 CPU 内存效率的对齐机制,多余位以 0 填充使得整个扫描行刚好占据整 4 字节的倍数那么大的一个内存块。这个在 24 位及以下的 BMP 标准中也是有的,每个扫描行必须始于 32 位内存区域的分界处。32 位无论如何都是 32 位对齐的,所以不会出现填充位。
[email protected]:~> repeat 1 fortune
Matz is nice, so we are nice.
回复 支持 反对

使用道具 举报

Lv4.逐梦者

弓箭手?剑兰

梦石
0
星屑
5529
在线时间
833 小时
注册时间
2010-11-17
帖子
1140
4
 楼主| 发表于 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
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
110
在线时间
953 小时
注册时间
2007-4-25
帖子
805
5
发表于 2011-5-29 01:09:47 | 只看该作者
一箭烂YiJL 发表于 2011-5-28 22:50
最初32位的时候我是扫点的,然后"插0",但是出现移位和颜色值错误...(加上倒置)
24位好像是没有了 a 通道 ...

最初32位的时候我是扫点的,然后"插0",但是出现移位和颜色值错误...(加上倒置)

32 位不用填充,3 楼已述。
24位好像是没有了 a 通道。

然也。
但是png是图片的每一行"插0",并不是每个颜色值。

BMP 也是,只要扫描行是 32 位对齐即可。
bmp貌似是Window的位图档案。

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

Ruby 对象的 `object_id' 是内存地址右移一位得到的,舍弃第 0 位。由于在 32 位取址的模型下,地址永远是 32 位对齐的,所以地址之间最小间距是 4。右移一位后最小间距变为了 2,也就是所有偶数的 ID 都被分配给了动态对象,而单数的 ID 就可以尽然分配给直接值使用(Fixnum、Symbol、TrueClass、FalseClass、NilClass)。因此,Ruby 的非直接对象底层的结构首地址就是 object_id << 1,相当于乘 2。

以前国外有人逆向分析出 Bitmap 的结构,大致如此:

  1. typedef struct rgss_bitmap_t rgss_bitmap_t;
  2. typedef struct rgss_bminfo_t rgss_bminfo_t;
  3. typedef struct bitmap_t bitmap_t;

  4. struct rgss_bitmap_t
  5. {
  6.     uint32_t flags;  
  7.     uint32_t klass;  
  8.     void (*dmark)(void*);  
  9.     void (*dfree)(void*);  
  10.     bitmap_t* bm;  
  11. }

  12. struct bitmap_t
  13. {
  14.     uint32_t unk1;  
  15.     uint32_t unk2;  
  16.     rgss_bminfo_t *bminfo;  
  17. }

  18. struct rgss_bminfo_t
  19. {
  20.     uint32_t unk1;
  21.     uint32_t unk2;
  22.     BITMAPINFOHEADER *infoheader;  
  23.     RGBQUAD *first;
  24.     RGBQUAD *last;
  25. }
复制代码
Object#object_id 拿到的是 rgss_bitmap_t 结构的地址,从该地址偏移 16 之后得到 rgss_bitmap_t#bm 这个指针域的地址,反引用之后寻址到 bitmap_t 结构的地址,偏移 8 后得到 bminfo 指针域地址,反引用后寻址到 rgss_bminfo_t 结构的地址,最后偏移 16 得到 last 这个指针域地址,而该指针指向的是位图像素第一行的地址,但实际上却是最后一个扫描行,所以命名为 last。

可以把 RtlMoveMemory 理解为纯 Ruby 反引用地址的一个工具。我们在 Ruby 中通过 API 拿到的内存地址并不能让我们直接操作其标识的内存,我们需要以某种方式把这段内存传输到 Ruby 可操纵的缓冲区中,也就是 Ruby 字符串。RtlMoveMemory 可以将一块内存整体拷贝到另一块缓冲区中,其第一个参数指定了目的地缓冲区的地址(你要拷贝的数据的目的地址),而第二个参数指定了源内存地址(你要拷贝的数据来源地址),第三个参数是长度。

Bitmap#address 里:
  1. RtlMoveMemory_pi.call(buffer, ad, 4)
复制代码
ad 是 object_id * 2 + 16,也就是上述 rgss_bitmap_t 结构体中 bm 域的地址;buffer 是一个 4 字节的 Ruby 字符串,接收了 rgss_bitmap_t#bm 所指向的内存的数据(也就是 bitmap_t 结构的地址,这里就是一个反引用地址的过程)。
  1. ad = buffer.unpack("L")[0] + 8
复制代码
现在 buffer 已经保存了 bitmap_t 结构首地址,偏移 8 之后得到 bitmap_t#bminfo 域的地址,赋给 ad。
  1. RtlMoveMemory_pi.call(buffer, ad, 4)
复制代码
ad 现在是 bitmap_t#bminfo 的地址,再次反引用地址,得到 rgss_bminfo_t 结构的首地址,拷贝到 buffer 中。
  1. ad = buffer.unpack("L")[0] + 16
复制代码
偏移 16,得到 rgss_bminfo_t#last 地址。
  1. RtlMoveMemory_pi.call(buffer, ad, 4)
复制代码
反引用,得到位图像素首地址。
  1. return buffer.unpack("L")[0]
复制代码
返回像素首地址。

好像在哪里说过实际的内存地址编号是左右调转的...(其实和上面的没什么关系)

你说的应该是小端序。小端序是一种字节(存储)序,表示最先储存的是最低有效字节,最后储存最高有效字节。i386 架构使用是小端序。

硬件使用小端序可以简化某些进行整数运算的电路设计。整数运算需要从最低有效位开始,进位时才转向更高的有效位,使用小端序就可以让整个运算不涉及到“回溯”,而是一直保持增加地址。大端序就需要先找到最低有效位,然后再“回溯”运算到最高有效位。

小端序还可以在不改变地址的情况下,获取到不同长度的相同整数值。比如——

01 00 00 00

这是小端序的“1”。读取 4 个字节传输到 32 位寄存器中,得到 01 00 00 00,值为 1;读取 2 个四节传输到 16 位寄存器中,得到 01 00,值为 1;读取 1 个字节传输到 8 位寄存器中,得到 01,值还为 1。

大端序的“1”则是:

00 00 00 01

无论寄存器长度,都需要把四个字节读入。

大端序的优势主要是在自然语言层面——今人所用之印度-阿拉伯数字体系,高位在左,低位在右。同时,很多人类口头语言也是“大端序”,如汉语的“九十四”,先提“九”,后提“四”。

点评

@yangff 还要进一步理解指针啊,嘿嘿。俗话说,理解了指针就掌握了 C!  发表于 2011-5-29 23:28
->yangff, 不对...说了指针占4,所以 :(0 -> unk1), (4 -> unk2), (8 -> *infoheader), (12 -> *first ), (16 -> *last)  发表于 2011-5-29 19:49
uint32_t unk1;-〉0 uint32_t unk2;->4 BITMAPINFOHEADER *infoheader; ->8 RGBQUAD *first;->16???? RGBQUAD *last;  发表于 2011-5-29 13:41
@yangff 偏移 0 是第一个域,以此类推。  发表于 2011-5-29 10:25
是last,指针占四个位。  发表于 2011-5-29 09:42
[email protected]:~> repeat 1 fortune
Matz is nice, so we are nice.
回复 支持 反对

使用道具 举报

Lv4.逐梦者

弓箭手?剑兰

梦石
0
星屑
5529
在线时间
833 小时
注册时间
2010-11-17
帖子
1140
6
 楼主| 发表于 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了= =
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
110
在线时间
953 小时
注册时间
2007-4-25
帖子
805
7
发表于 2011-5-29 12:17:48 | 只看该作者
一箭烂YiJL 发表于 2011-5-29 09:42
谢谢~现在明白怎么能够拿到颜色值数据地址了,原来都是这些指针(和结构体的位偏移),
但为什么要让结构体 ...
但为什么要让结构体里的指针指来指去?

做面向对象编程的时候,为什么要设计这么多类,又让类的成员引用来引用去?

为什么要 RGBQUAD 定义两个指针(first 和 last)?

rgss_bminfo_t#last 是实际的像素数据开头,方便用户从这里直接拷贝整块数据;rgss_bminfo_t#first 是实际的像素数据的最后一行开头,不过在映射到输出设备(显示器)后就会变成第一行,这方便了用户直接通过 rgss_bminfo_t#first 指针进行扫描行的翻转,也就是从 rgss_bminfo_t#first 开始扫描一行,每次偏移负的一行那么多字节(first -= 宽度 until first == last)。

这样最后的一次RtlMoveMemory之前的偏移 16 改成偏移 12 也一样啊~

看要做什么了。像这个脚本就可以在 rgss_bminfo_t#first 这个位置开始拷贝数据,然后逆向偏移 rgss_bminfo_t#first。这里做了翻转就是因为 GDI 返回的位图数据是设备相关的,没有像设备无关的 BMP 格式那样被翻转。

然后我根据国外分析的结构,在最后 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 的某些值不同是无所谓的吧~

应该是可以直接存进 BMP 的。

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

和 32 位格式无压缩 BMP 格式没有区别。BMP 支持所有的色深模式,比如 24 位真彩色,16 位高彩色,8 位 256 索引色,4 位 16 色,2 位 4 色,1 位单色(黑白)等等。同时 BMP 还有自己的压缩标准,支持简单的 RLE、霍夫曼压缩,当然基本没什么实用价值。

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

写解码器的工作量还是挺大的,像 ffmpeg 这样的工程基本上不可能一个人完成。不过,在钻研的过程中确实能学到不少知识 :)

点评

GIF 不用想了,效率够呛  发表于 2011-5-29 13:43
[email protected]:~> repeat 1 fortune
Matz is nice, so we are nice.
回复 支持 反对

使用道具 举报

Lv4.逐梦者

弓箭手?剑兰

梦石
0
星屑
5529
在线时间
833 小时
注册时间
2010-11-17
帖子
1140
8
 楼主| 发表于 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
星屑
1347
在线时间
676 小时
注册时间
2009-11-11
帖子
2790
9
发表于 2011-5-29 20:58:32 | 只看该作者
强大的东西

点评

API 函数。  发表于 2011-5-31 16:40
可以用RtlMoveMemory,颜色值 32 位 bmp 图案首选(少点工序)。  发表于 2011-5-30 17:57
你说文件标志,每个格式都不同。我说的是BitmapInfoHeader,是其中一个数据流。记录了一些位图的讯息。  发表于 2011-5-29 21:16
后来发现 BitmapInfoHeader 也可以从内存拷贝过来的(6楼~7楼)。  发表于 2011-5-29 21:03

嘿。嘿。嘿
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
110
在线时间
953 小时
注册时间
2007-4-25
帖子
805
10
发表于 2011-5-30 02:25:11 | 只看该作者

RE: Bitmap 类储存为 .bmp 档案(高速= =)

一箭烂YiJL 发表于 2011-5-29 16:29
但我认为非 Ruby 的话,不需要这样指来指去。(Ruby 接驳的 C 就不知道了)
但我认为非 Ruby 的话,不需要这样指来指去。(Ruby 接驳的 C 就不知道了)

先声明一点,“引用”的概念是计算机科学中的一个通用概念,并非面向对象的语言的专利。只不过当我们在面向对象语言上下文中提起引用时,通常是特指被 GC 管理的引用。下文的“引用”均泛指间接访问另一个实体的名称绑定的概念,而非 GC 管理的特殊引用。

在面向对象的语言中,一个类的成员可以引用(绑定)一个类的实例,建立 has-a 关系。同样地,在 C 中一个结构也可以和一个实体(可以是原始数据类型结构体联合体或是枚举的实例)建立 has-a 关系,而 C 引用实体的方式就是指针。当使用了引用后,就有了以下好处:

1、引用的实体的存储位置更加灵活

结构的成员引用的实体所占据的内存可以是在任何有效的位置分配的。之后即便是结构本身迁移了,只要引用没有改变,我们仍然可以间接访问到实体,而不需要连实体本身也一并迁移。比如:你来到办公大楼南门的接待处,要找张三(实体),接待员(引用)告诉你张三的房间号(地址)。两个月后,接待处搬迁到北门,但张三的房间号没变,你只要能去北门的接待处,仍然可以访问到同一个张三。

2、引用的实体的分配方式更加灵活

结构的成员引用的实体所占据的内存可以是以任何有效的方式分配的——可以分配为局部栈内存、动态堆内存、静态全局内存甚至是常量内存。我们的结构只是引用它,我们并没有创造它、分配它。比如:接待处的接待员可能根本就不认识张三,也不知道他是什么时候来这幢楼上班的,但总之他有(从上司那里拿到的)张三的楼层和房间号,能让来宾间接访问到他。

3、轻量化

结构的成员引用的实体本身可能是很庞大的,如果某个成员不是结构的引用而直接是结构的值,那么相应的包容了这个结构的容器结构也会变得很庞大。每次对容器结构进行传递或是赋值操作时,都会涉及到整个结构的拷贝,其开销是和结构体大小成正比的。比如:

  1. struct A
  2. {
  3.     int a, b, c, d, e, f, g, h;
  4. };

  5. struct B
  6. {
  7.     struct A a;
  8.     struct B b;
  9. };

  10. struct B b;
  11. struct A a;
  12. b.a = a;
复制代码
sizeof (A) = 32 字节。由于 B#a 和 B#b 都不是指针类型,而是结构实体(值)本身,所以 sizeof (B) = 64 字节。`b.a = a;' 这一句,就要涉及到 32 个字节的拷贝。如果让 B#a 和 B#b 都变为指针,sizeof (A) 就可以是 8 字节,而 `b.a = a;' 也仅仅是 8 个字节的拷贝而已。在函数传参的时候,也需要考虑类似的问题——传值还是传引用。

4、共享内存

两个结构可能都有一个某类型的成员,但希望能共享其实体,而不是各自拥有一份拷贝。这时使用引用,就可以实现共享。比如:张三(实体)可能是一位知名的经纪人,并且全市独一无二。客户无论是去城西的介绍所和还是去城东的介绍所都能通过当地的工作人员获取到张三的引用并间接找到张三真正的位置。这样一来,就不需要在两个介绍所都安插自己的相互独立的经纪人。

当然,以上只是为了说明为什么要在结构中用引用。实践时合理地在结构体里直接包含另一个结构的值也是可能的。比如一个结构体本身就需要这么多值域,其中一部分可以单独被包装到另一个合理的结构(命名空间)中统一管理,但实际上整个大结构仍然是连续的内存。

很多编程思想其实并不限于语言,像 C 就完全可以写出带面向对象味道的代码,只是很多人不承认这一点而已。

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

指针位置(指针的地址)肯定是不同的,除非 16 == 12。如果你是说指针指向的地址(指针的值),我这里测试是不同的,不知道你那边是如何测试的。

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

http://msdn.microsoft.com/en-us/library/dd183376(v=vs.85).aspx
第六个域是压缩方式,第七个域是图像(字节)大小。未经压缩的不需要这个值也能确定大小,所以如果格式为 BI_RGB,biSizeImage 就为 0。

summer92  话说同格式的文件类型jpg,png,bmp文件头应该一样的把,音乐格式也是,- -

很多都不同。16 位以上 BMP 格式是简单的头 + 像素数据;8 位及 8 位以下的 BMP 格式是头 + 调色板 + 索引表。JPEG 格式是分段的,每一段都有各自的作用,像图像开头、结尾、霍夫曼表、注释等等都自成一段;每段由一个标记开头,每个标记两个字节,由 0xff 开头。GIF 也是分段的,只不过段落开头的标记是一个字节(即没有像 JPEG 那样固定的 0xff)。PNG 在开头会有 8 个固定字节的签名。音频格式泰半也都不同。

点评

比如一些模型开头 16进制 是一样的,这样才能知道 开头和结尾,如果图片不同的话(大部分相同),应该也有办法筛选出来,嘿嘿  发表于 2011-5-31 15:05
文件头虽然不统一,但大致上还是有特征的,所以 RM 才能不通过扩展名来识别媒体格式  发表于 2011-5-30 10:12
哦..哦,话说解包一些东西,得靠文件头来判断文件类型啊,都不相同的话,那就头疼了  发表于 2011-5-30 09:53

评分

参与人数 1星屑 +400 收起 理由
夕阳武士 + 400 鼓励各种讨论=w=

查看全部评分

[email protected]:~> repeat 1 fortune
Matz is nice, so we are nice.
回复 支持 反对

使用道具 举报

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

本版积分规则

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

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

GMT+8, 2024-11-24 01:29

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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