Project1

标题: 快速存储Bitmap的Marshal(高难度API,不解释) [打印本页]

作者: 柳之一    时间: 2008-5-27 00:31
标题: 快速存储Bitmap的Marshal(高难度API,不解释)
vx xp均可以使用
object_id * 2 + 16 这个是关键中的关键。详细的部分请调查ruby的资源的rb_obj_id和DATA_PTR这个部分。

io形式等等按照自己的需求来自己设定
  1. class Font
  2. def marshal_dump;end
  3. def marshal_load(obj);end
  4. end
  5. class Bitmap
  6. # 传送到内存的API函数
  7. RtlMoveMemory_pi = Win32API.new('kernel32', 'RtlMoveMemory', 'pii', 'i')
  8. RtlMoveMemory_ip = Win32API.new('kernel32', 'RtlMoveMemory', 'ipi', 'i')
  9. def _dump(limit)
  10. data = "rgba" * width * height
  11. RtlMoveMemory_pi.call(data, address, data.length)
  12. [width, height, Zlib::Deflate.deflate(data)].pack("LLa*") # 压缩
  13. end
  14. def self._load(str)
  15. w, h, zdata = str.unpack("LLa*"); b = new(w, h)
  16. RtlMoveMemory_ip.call(b.address, Zlib::Inflate.inflate(zdata), w * h * 4); b
  17. end
  18. # [[[bitmap.object_id * 2 + 16] + 8] + 16] == 数据的开头
  19. #
  20. def address
  21. buffer, ad = "xxxx", object_id * 2 + 16
  22. RtlMoveMemory_pi.call(buffer, ad, 4); ad = buffer.unpack("L")[0] + 8
  23. RtlMoveMemory_pi.call(buffer, ad, 4); ad = buffer.unpack("L")[0] + 16
  24. RtlMoveMemory_pi.call(buffer, ad, 4); return buffer.unpack("L")[0]
  25. end
  26. end
复制代码
注意,这个脚本对于增强你的游戏性没有什么帮助,是关于如何储存图片的。
能打算使用这个的也是不需要范例的,要范例的估计也用不到。

不知道能不能解决 沉影不器 的 求把缓存里的bitmap压入存档的有效率的办法。如果不是的话,请原谅在下。
作者: Elegance    时间: 2008-5-27 04:27
提示: 作者被禁止或删除 内容自动屏蔽
作者: 柳之一    时间: 2008-5-27 04:46
以下引用Elegance于2008-5-26 20:27:01的发言:

沉了,好东西帮你顶下。

谢谢你,本来准备pm他的,谁知pm不了 [LINE]1,#dddddd[/LINE]系统信息:本贴由本区版主认可,66RPG感谢您的热情解答~
作者: 沉影不器    时间: 2008-5-27 04:55
提示: 作者被禁止或删除 内容自动屏蔽
作者: 沉影不器    时间: 2008-5-27 05:02
提示: 作者被禁止或删除 内容自动屏蔽
作者: 柳之一    时间: 2008-5-27 05:05
对你有用就好。哎,我竟发这样非大众化的脚本,哪怕只有你一个知音,就满足了。
作者: ★_茄孓    时间: 2008-5-27 05:06
那沉影你的VX新菜单截图是不是有点卡,可以更新换上效率好的?
作者: 沉影不器    时间: 2008-5-27 05:14
提示: 作者被禁止或删除 内容自动屏蔽
作者: 禾西    时间: 2008-5-27 06:17
{/fd},這個東西好有用啊。柳一兄眞厲害
[LINE]1,#dddddd[/LINE]
添加一下語句解釋:
=begin

RtlMoveMemory(API 函數)
  說明:將指定之記憶體範圍移動到新的位置
       (對於內存進行讀取或修改)
  參數說明:p -想要移動的內容(字符串)
            i -移動的地址(整數)
            i -複製的字節數(整數)
  返回值  :沒有查到(毆~)

Zlib::Inflate.inflate( ) (壓縮方法)
  作用:把整數壓縮成字符串
  說明:把整數寫( )之內就可以了
Zlib::Deflate.deflate( ) (壓縮方法)
  作用:與上面相反
  
"rgba" * width * height  (String 類方法)
  作用:擴展字符串
  說明:看以下例子
        "abc" * 2 #=>"abcabc"
      
new(w, h)    (Bitmap 類方法)
  作用:生成指定尺寸的 Bitmap 對象
  說明:常用形式爲 Bitmap.new(width, height)
        因爲這裏是 class Bitmap 內部調用,所以可以簡化爲 new(width, height)

string.unpack() (String 類方法)
  作用:.unpack 會有把一個字符串轉換爲數組(Array)
  說明:.unpack( )需要帶有參數說明轉換的方法
         (LLa*)代表把字符轉換爲以下樣式的數組:
  array=[
         unsigned native long integer(整數),
         unsigned native long integer(整數),
         string(字符串),
         ]
         最後的 * 表示會使用完字符串當中所有的元素

array.pack()    (Array 類方法)
  作用:把數組(Array)轉換爲字符串(String)
  參數說明參考 .unpack

* .pack() 與 .unpack() 的作用是實現數組(Array)與字符串(String)的互相轉換
  
buffer, ad = "xxxx", object_id * 2 + 16 (賦值方法)
  作用:同時賦值兩個變量
  說明:Ruby 語句允許同時給多個變量賦值
        左邊的「變量」會取得右邊相應位置的「數值」
        使用時格式應該爲:
        a , b, c = avalue, bvalue, cvalue
  注意:= 號的左右兩邊元素量可以不等
        如果「值」數量多於「變量」數量會忽略多餘值
        如果「變量」數量多於「值」數量,多餘的「變量」會有得到「nil」值
        如果左邊只有一個「變量」而右邊多於一個「值」會賦成爲數組
=end

具體怎麼用不知道 (毆)
作者: 雪流星    时间: 2008-5-27 14:06
這個只加150分太少了
禾西轉到VX區讓我來發布吧{/dy}
作者: 沉影不器    时间: 2008-5-27 17:19
提示: 作者被禁止或删除 内容自动屏蔽
作者: 禾西    时间: 2008-5-27 18:07
以下引用沉影不器于2008-5-27 9:19:17的发言:

RtlMoveMemory参数好像是:
1目的地址
2源地址
...

Zlib::Inflate.inflate 一直只知道个大概,超过那个参考手册的全都不懂

"rgba" * width * height  开辟空间

那個API的參數我也查不到,好像是這樣子(毆)

Zlib::Inflate.inflate的作用是把 展開的String 還原成
也就是那個
x\004\125\142
之類的。作用啊....我都不知道 Orz
作者: Elegance    时间: 2008-5-28 02:01
提示: 作者被禁止或删除 内容自动屏蔽
作者: 柳之一    时间: 2008-5-28 04:08
以下引用Elegance于2008-5-27 18:01:31的发言:

http://tkool.web-ghost.net/wiki/wiki.cgi?page=Script%2FBitmap%A4%CEMarshal%C2%D0%B1%FE

http://jbbs.livedoor.jp/bbs/read.cgi/game/14836/1090833499/856


最终更新时间:2008年02月05日 23时46分45秒
投稿日: 2008/02/04(月) 19:26:05…………无言。

显然您不知道我在日站的身份,呵呵。除了法国的那个网站,基本上一些日站和英站都有我的id的。{/cy}
顺便说一下,那个wiki是用的2ch的。

2chって、なんにもいえないよ。2chはこのスクリプトのちょさくけんを持たないよ。このスクリプトは複数の人たちが論討したけっかだ、だれが投稿したのはわからない{/dy}
作者: yangff    时间: 2008-5-28 04:46
呵呵,脚本的实用性。话说到底是做什么的?
作者: 柳之一    时间: 2008-5-28 04:48
以下引用yangff于2008-5-27 20:46:25的发言:

呵呵,脚本的实用性。话说到底是做什么的?

对其他人基本没有用,只是给沉影不起的在存档里高速存储图片用的。
作者: link006007    时间: 2008-5-28 05:56
哈`~!   来的正好   问lz一个问题(我基本卡死这地方了...):

一个指向 C++ 类的指针如何能被 ruby的Data_Wrap_Struct转换成VALUE?
其实不一定要Data_Wrap_Struct 只要能够被ruby保存就好

我建立了一个C的结构体保存C++类的指针, 然后把C结构体拿来Data_Wrap_Struct也会出错
不知道具体要怎么做...

typedef struct _holdCXXPTR{
    VALUE klass;
    void* pData;     // 保存C++PTR的, 本来想通过保存C结构体来保存C++类指针...
    ... ...
}HOLDCXXPTR;
作者: 柳之一    时间: 2008-5-28 06:02
以下引用link006007于2008-5-27 21:56:13的发言:

哈`~!   来的正好   问lz一个问题(我基本卡死这地方了...):

一个指向 C++ 类的指针如何能被 ruby的Data_Wrap_Struct转换成VALUE?
其实不一定要Data_Wrap_Struct 只要能够被ruby保存就好

我建立了一个C的结构体保存C++类的指针, 然后把C结构体拿来Data_Wrap_Struct也会出错
不知道具体要怎么做...

typedef struct _holdCXXPTR{
   ;VALUE klass;
   void* pData;     // 保存C++PTR的, 本来想通过保存C结构体来保存C++类指针...
   ... ...
}HOLDCXXPTR;

莫非林克想把rm搬到c++上?
作者: link006007    时间: 2008-5-28 06:22
直接把SWIG那些宏拷过来用了。。。
作者: 沉影不器    时间: 2008-6-1 04:19
提示: 作者被禁止或删除 内容自动屏蔽
作者: 柳之一    时间: 2008-6-1 05:03
以下引用沉影不器于2008-5-31 20:19:08的发言:

原来您在日站深造,难怪这个脚本的书写习惯看着很不爽,我给改写了一下

没有办法,大陆这里讨论技术气氛不够……{/gg}
2.5行脚本 = 让数值输入有个默认值
从这个帖子就能看出来吧,呵呵
作者: 禾西    时间: 2008-6-1 14:59
發布。柳之一.VIP += 3
作者: 洛克人SZ    时间: 2008-6-2 00:44
太强大了,之前这种功能我是用数组化+写入文件来实现的,效率太差了,果然我还是需要
加强 API 方面的知识…………
作者: 轮回者    时间: 2008-6-3 21:29
强大{/qiang}

似乎不压缩的数据加个文件头减去透明值就是BMP文件,压缩的数据加个文件头可以改成PNG文件.

作者: 轮回者    时间: 2008-6-3 21:32
"rgba" 指的是红,绿,蓝,透明
是储存图片中某一点要用的4个参数.


作者: 柳之一    时间: 2008-6-4 03:45
以下引用轮回者于2008-6-3 13:32:08的发言:

"rgba" 指的是红,绿,蓝,透明
是储存图片中某一点要用的4个参数.

好久不见。

话说,夏娜的那个输出图片的脚本好像就是用png的文件头然后逐点输出的
作者: 轮回者    时间: 2008-6-4 19:40
好久不见

这个存的也是点阵吧,高考后我如果有空到是可以用这个做个图象输出。

不知道用这个来读取GIF速度是否会加快。

还有,似乎可以用这个来重写一个Bitmap,甚至支持影像也不是不可能,但以我菜鸟级的编程水平和RUBY语言的执行速度…还是算了
作者: yangff    时间: 2008-6-4 19:43
所以能直接把Bitmap实例存储效率会提升很多
循环的效率是最最差的
作者: 落痕    时间: 2008-7-25 09:27
提示: 作者被禁止或删除 内容自动屏蔽
作者: 沉影不器    时间: 2008-8-5 01:16
提示: 作者被禁止或删除 内容自动屏蔽
作者: 沉影不器    时间: 2008-8-6 18:48
提示: 作者被禁止或删除 内容自动屏蔽
作者: 柳之一    时间: 2008-8-6 20:55
我晕,你的短信竟然没有开{/gg}
参见ruby资源的rb_obj_id,还有DATA_PTR

我的ruby删了,不好意思麻烦您自己下吧。
里面有关于操作内存和Font的marshal

作者: 沉影不器    时间: 2008-8-9 04:16
提示: 作者被禁止或删除 内容自动屏蔽
作者: 静音    时间: 2008-8-9 19:59
提示: 作者被禁止或删除 内容自动屏蔽
作者: link006007    时间: 2008-8-9 20:09
我一直很好奇  
我觉得  最关键是lz最早是怎么得到bitmap的图像数据是保存在Bitmap实例内存首地址偏移这么多的量之后的内存地址中的
作者: 柳之一    时间: 2008-8-9 20:17
以下引用link006007于2008-8-9 12:09:57的发言:

我一直很好奇  
我觉得  最关键是lz最早是怎么得到bitmap的图像数据是保存在Bitmap实例内存首地址偏移这么多的量之后的内存地址中的


日本的一个程序员告诉我的
作者: link006007    时间: 2008-8-9 20:25
{/ll}  你不会是那个程序员吧~~~
哎  劫狱去...{/hx}
作者: hide秀    时间: 2008-8-10 00:21
这个帖子这么受人关注了
先不管柳之一这些内部方法怎么得到的
柳之一不解释。。。。
。。。我来解释下这个强贴吧
我到后面也有些疑问,麻烦柳之一解释下吧
如有分析的不对的地方,请指正{/hx}
[quote]
RtlMoveMemory_pi = Win32API.new('kernel32', 'RtlMoveMemory', 'pii', 'i')
RtlMoveMemory_ip = Win32API.new('kernel32', 'RtlMoveMemory', 'ipi', 'i')
一个是 传送字符串到内存 参数1:字符串 参数2:地址 参数3:长度
另一个 传送整型到内存   参数1:整型   参数2:地址 参数3:长度

def _dump(limit)
data = "rgba" * width * height
RtlMoveMemory_pi.call(data, address, data.length)
[width, height, Zlib::Deflate.deflate(data)].pack("LLa*") # 压缩
end

这个方法是开辟临时内存空间的
"rgba"看作是4个字节
data = "rgba" * width * height
像素的集合块(其实是开辟内存空间,并没有实质内容,就是字符串"rgba"的循环)

RtlMoveMemory_pi.call(data, address, data.length)
把像素集合块存储到内存地址
记得这个定义的时候是传送字符串么 就是把"rgba"的字符串循环存入
实际已经占用了内存
参数指定了数据块,要传送的地址,数据块长度

[width, height, Zlib::Deflate.deflate(data)].pack("LLa*")
这个是把宽度,高度,数据组成的数祖转换成2进制形式字符串组
这里转换3个数据
第一和第二个是把bitmap的 宽度,高度打成长型(一个字节用C,超过一个字节用I或者L)
第三个a*是先把数据块所有字符串用Zlib压缩成压缩数据 然后打包成ASCII形式
不过这个不知道这么做有啥用。。
纯粹打包下成字符串 也没有带入变量
请柳之一解释。。

def self._load(str)
w, h, zdata = str.unpack("LLa*"); b = new(w, h)
RtlMoveMemory_ip.call(b.address, Zlib::Inflate.inflate(zdata), w * h * 4); b
end

这个是定义从内存读取像素点阵块

w, h, zdata = str.unpack("LLa*");
记得之前的方法最后已经把数据打包成的字符串组么
这个就是把字符串组里面的数据打包还原成数组
感觉和之前那个没有带入变量的字符串组有点联系{/gg}
并且分别传给变量w,h,zdata(还未Inflate)

b = new(w, h)
生成bitmap对象 带入b

RtlMoveMemory_ip.call(b.address, Zlib::Inflate.inflate(zdata), w * h * 4); b
把Inflate后的zdata数据 存入对象偏移后的地址(这个稍后解释)
这个api定义的时候是i型的 因为存入的是实际rgba像素值和透明度值了
并不是之前那个定义为p的"rgba"临时字符串组 这些小细节不知道大家注意了没有{/wx}

def address
buffer, ad = "xxxx", object_id * 2 + 16
RtlMoveMemory_pi.call(buffer, ad, 4); ad = buffer.unpack("L")[0] + 8
RtlMoveMemory_pi.call(buffer, ad, 4); ad = buffer.unpack("L")[0] + 16
RtlMoveMemory_pi.call(buffer, ad, 4); return buffer.unpack("L")[0]
end

这个adress方法就是定义要存入的地址
返回的是一个地址
buffer, ad = "xxxx", object_id * 2 + 16
buffer = "xxxx"  定义字符串"xxxx"
ad = object_id * 2 + 16   定义初始化内存偏址
object_id是 是这个bitmap对象的内部分配的id
根据ad = object_id * 2 + 16 判断
这个object_id 和对象存放数据的地址有关

RtlMoveMemory_pi.call(buffer, ad, 4)
把字符串"xxxx"存入初始化内存 地址为:object_id * 2 + 16

ad = object_id * 2 + 16
ad = buffer.unpack("L")[0] + 8
ad = buffer.unpack("L")[0] + 16

这三个地址分别 存入4个字节 也就是 "xxxx"

概括就是 存入四个字节"xxxx" 偏移4个字节
再存入四个字节"xxxx" 偏移12个字节
再存入四个字节"xxxx"
不知道有什么用....{/gg}

最后返回的是
return buffer.unpack("L")[0]
应该是实际数据要存入的内存地址

解释完毕....

我也补充下疑问...
return buffer.unpack("L")[0]
应该是实际存放地址开始部分
但是之前的注释
# [[[bitmap.object_id * 2 + 16] + 8] + 16] == 数据的开头
应该是相等的地址。。。。
但怎么想也联系不到一起。。。{/gg}
其实也就是object_id 和 buffer.unpack("L")[0] 的关系
麻烦柳之一解释下。。。{/wx}



作者: link006007    时间: 2008-8-10 04:02
ls...  写了这么长... 没说到我想要的{/dk}
作者: 沉影不器    时间: 2008-8-10 06:26
提示: 作者被禁止或删除 内容自动屏蔽
作者: link006007    时间: 2008-8-10 10:50
半夜睡不着, 爬上来研究这个脚本果然很有催眠效果{/gg}
lz会写这个脚本, 应该可以自己DIY  ruby了吧?
以下引用沉影不器于2008-8-9 22:26:18的发言:object_id * 2 + 16<---这个楼主很早就说明了在ruby资源文件里头说的
这脚本的伟大还在于真的需要了解到很多内部类的构成啊啊啊...

不会就是rb_obj_id 函数体里那段注释吧?  没看出来和object_id*2有什么关系{/gg}
到现在也没看懂 ruby的对象的self和他对应的C结构体指针怎么算...
找到对应函数, 看不懂里面过程{/gg}
作者: 沉影不器    时间: 2008-8-10 17:20
提示: 作者被禁止或删除 内容自动屏蔽
作者: dna_7086    时间: 2008-8-11 20:38
提示: 作者被禁止或删除 内容自动屏蔽
作者: danny8376    时间: 2008-8-13 05:57
以下引用dna_7086于2008-8-11 12:38:50的发言:


以下引用link006007于2008-8-9 12:09:57的发言:

我一直很好奇  
我觉得  最关键是lz最早是怎么得到bitmap的图像数据是保存在Bitmap实例内存首地址偏移这么多的量之后的内存地址中的



你用OllDBG跟踪GAME.EXE试试吧,应该也能得到吧...


跟踪没用
因为主程序是RGSSX0XX.dll
而且这还是个直译器
能得到什么东西啊
还不就一堆直译器的指令



楼主
想问一下address
最后传回的是內存的实体地址
还是RGSS内部的地址


顺便介绍一下此脚本吧


# 贴上此脚本后
# 可直接用Marshal模组读写Bitmap类
# 不需多做修改
# 介绍一下Marshal模组运作原理
# 以脚本呈现
# 不代表实际执行的脚本
# def Marshal.dump(obj, port = nil, limit = 100)
#   result = # obj._dump(limit) or obj.marshal_dump 其中一个
#   return result if port == nil
#   写入 result 至 port
# end
# def Marshal.load(port)
#   dat = 读取 port
#   return # obj._load(dat) or obj.marshal_load(dat) 其中一个
# end
# 上面的 写入 和 读取 为一些IO的指令
class Font
  # Marshal.dump 对类调用的主程序
  def marshal_dump
  end
  # Marshal.load 对类调用的主程序
  def marshal_load(obj)
  end
  # 上面的方法没定义内容是因为
  # Font类对Bitmap类中的存储不重要
  # 而预设Font类也没有这2个方法
end
class Bitmap
  # 传送到内存的API函数
  # 读取内存用 参数为 字串 整数 整数
  RtlMoveMemory_pi = Win32API.new('kernel32', 'RtlMoveMemory', 'pii', 'i')
  # 写入内存用 参数为 整数 字串 整数
  RtlMoveMemory_ip = Win32API.new('kernel32', 'RtlMoveMemory', 'ipi', 'i')
  # 在此整数为1字节的整数
  # Win32API 会帮忙转换
  # 供 Marshal 模组用的写入方法
  def _dump(limit) # limit 为 深度限制 但这里忽略不使用
    # 生成 4 * width * height 个字节的字串
    # 所以 "rgba" 可换成 任何4字节的字串 如 "\000" * 4
    # 在此为 RtlMoveMemory_pi 生成所需的内存空间
    data = "rgba" * width * height
    # 调用 RtlMoveMemory_pi 读取
    # 以address为地址
    # 长度为data.length ( 即 4 * width * height )
    # 的内存资料 并存入 data 中
    RtlMoveMemory_pi.call(data, address, data.length)
    # 将 [width, height, Zlib::Deflate.deflate(data)] 打包
    # [width, height, Zlib::Deflate.deflate(data)]
    # width,  height 为图片宽度 ( Bitmap 内属性 )
    # Zlib::Deflate.deflate(data)为压缩 data 内的文字 (GZip)
    # 至于 Array.pack 的参数是什么不重要
    # 只要跟 String.unpack 的参数一样就好
     # ※ 回传给 Marshal.dump 的资料必须为 String ( 字串 ) 类物件
    #   因为 _dump 或 marshal_dump 的工作即为
    #   将该类物件转为字串给 Marshal.dump 存入
   [width, height, Zlib::Deflate.deflate(data)].pack("LLa*") # ??
  end
  # 供 Marshal 模组用的读取方法
  def self._load(str) # str 为 Marshal.load 读出的字串
    # 解包 str
    # 并将解包后的阵列([width, height, data(压缩后)])
    # 分别存入w, h, zdata
    # w => width, h => height, zdata => data(压缩后)
    w, h, zdata = str.unpack("LLa*")
    # 生成 以 w 和 h 为宽高的图片
    # new 为继承 Object 的方法
    # 因此在任何物件中都有此方法
    b = new(w, h)
    # 调用 RtlMoveMemory_ip 修改
    # 以b.address为地址
    # Zlib::Inflate.inflate(zdata) 为资料
    # Zlib::Inflate.inflate(zdata) 为解压缩 zdata 内的文字 (GZip)
    # 长度为 w * h * 4
    # 的内存资料
    RtlMoveMemory_ip.call(b.address, Zlib::Inflate.inflate(zdata), w * h * 4)
    # 回传 b
    # 在 Ruby 中无 return 的话
    # 会自动回传最后一个指令的回传值
    b
  end
  # [[[bitmap.object_id * 2 + 16] + 8] + 16] == 数据的开头
  def address
    # 定义 buffer 和 ad 为 "xxxx" 和 object_id * 2 + 16
    # 这是Ruby的多重指定
    # 左边超过右边时 超出的部份不会带入数值 ( 即同于带入 nil )
    # 右边超过左边时 超出的部份不管
    # 但左边最后一个变量以*开头时
    # 超出部份会以阵列带入该变量
    # 左边1个而右边超过1个时
    # 同于 *变数 = 值1, 值2, ...
    buffer, ad = "xxxx", object_id * 2 + 16
    # 下方为以 RtlMoveMemory_pi 逐步取得地址
    # 在此不做说明
    RtlMoveMemory_pi.call(buffer, ad, 4)
    ad = buffer.unpack("L")[0] + 8
    RtlMoveMemory_pi.call(buffer, ad, 4)
    ad = buffer.unpack("L")[0] + 16
    RtlMoveMemory_pi.call(buffer, ad, 4)
    # 回传 buffer.unpack("L")[0]
    # buffer.unpack("L") 在此不做说明
    return buffer.unpack("L")[0]
  end
end

作者: 灼眼的夏娜    时间: 2008-8-31 18:04
以下引用沉影不器于2008-8-10 9:20:20的发言:

我没下载那些什么ruby资源之流,我是先默认'object_id*2 + 16'成立,那么所有内存操作都明显成立了.

。。。。并不都是这样的。。。。  这个16是和扩展类的data指针偏移对应的……{/gg}




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