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

Project1

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

[原创发布] ImageEx

[复制链接]

Lv4.逐梦者

梦石
0
星屑
6483
在线时间
119 小时
注册时间
2020-1-8
帖子
234
跳转到指定楼层
1
发表于 2022-11-29 17:28:16 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

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

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

x
本帖最后由 RPGzh500223 于 2022-11-30 14:57 编辑

感觉很鸡肋,电脑里扔了2个多月,毕竟都写了,发贴混点经验。
ImageEx_rmxp.dll  VS2015  C++语言编写(因为有库是C++的,其实都是按C写的)。


RUBY 代码复制
  1. module ImageEx
  2.   dll = "ImageEx_rmxp.dll"
  3.  
  4.   # ———— png 与 jpeg ——————————————————
  5.   # 仅支持 jpeg(Gray/RGB)、png(Gray/GrayAlpha/RGB/RGBA)
  6.   # 使用libjpeg/libpng
  7.   # ————————————————————————————
  8.  
  9.   # 支持的模式会转换至BGRA,不支持的模式会返回-1。
  10.   # filename_uft8, bitmap_obj_id
  11.   Load_JPG = Win32API.new(dll, 'bitmap_load_jpg', 'PL', 'L')
  12.   # filename_utf8, bitmap_obj_id
  13.   # channels  1或3    BGRA会转换至支持的对应模式
  14.   # quality   0..100  质量越好,文件越大
  15.   Save_JPG = Win32API.new(dll, 'bitmap_save_to_jpg', 'PLLL', 'L')
  16.  
  17.   # 支持的模式会转换至BGRA,不支持的模式无效操作。
  18.   # filename_uft8, bitmap_obj_id
  19.   Load_PNG = Win32API.new(dll, 'bitmap_load_png', 'PL', 'L')
  20.   # filename_utf8, bitmap_obj_id
  21.   # channels  1..4  BGRA会转换至支持的对应模式
  22.   Save_PNG = Win32API.new(dll, 'bitmap_save_to_png', 'PLL', 'L')
  23.  
  24.  
  25.   # ———— gif 与 webp ——————————————————————————
  26.   # 仅支持读取,无论是否使用线程(Win32 CreateThread)都需要释放(调用dispose)
  27.   # gif中disposal_method不支持DISPOSE_PREVIOUS
  28.   # 播放效果视文件而定,可能会“画面闪烁”
  29.   # 效率:非线程模式,640*480大小,读取一帧 gif:1000次/秒 webp:300次/秒
  30.   #            参照,640*480大小的Bitmap#blt    260+次/秒         
  31.   # 使用libgif/libwebp
  32.   # ————————————————————————————————————
  33.  
  34.   # filename_utf8   : utf8编码的文件名。
  35.   # sprite_obj_id   : RMXP 精灵(Sprite) 对象的 object_id,精灵需设置好其位图。
  36.   # gif_cell_string : GIF_CELL_SIZE字节的字符串,用来保存一些数据。
  37.   # play_mode : 0..3位 是否抠图。抠图效果不错,对效率影响不大。      
  38.   #                    1:抠除黑色;2:抠除白色;其他(0/3):原图。
  39.   #             4..7位 是否线程模式。  0:不使用;非0:使用。
  40.   # loop_count : 自定义播放次数。 0:文件默认次数;负数:一直播放;正数:指定次数。
  41.   Show_GIF = Win32API.new(dll, 'show_gif', 'PLPLL', 'L')
  42.   Draw_GIF = Win32API.new(dll, 'draw_gif', 'L', 'L')
  43.   Free_GIF = Win32API.new(dll, 'free_gif', 'L', 'L')  
  44.   GIF = 0x666967
  45.   GIF_CELL_SIZE = Show_GIF.call(nil, 0, 0, 0, 0)
  46.  
  47.   # 参数四 mode : 是否线程模式。  0:不使用;非0:使用。
  48.   # 其余参数,参见Show_GIF
  49.   Show_WEBP = Win32API.new(dll, 'show_webp', 'PLPLL', 'L')
  50.   Draw_WEBP = Win32API.new(dll, 'draw_webp', 'L', 'L')
  51.   Free_WEBP = Win32API.new(dll, 'free_webp', 'L', 'L')  
  52.   WEBP = 0x70626577
  53.   WEBP_CELL_SIZE = Show_WEBP.call(nil, 0, 0, 0, 0)
  54.  
  55.   # 这两个方法其实没什么用……
  56.   def self.get_png_wh(filename)
  57.     w = h = 0
  58.     File.open(filename, 'rb') do |f|
  59.       if f.read(8) == "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A"
  60.         f.seek(8, IO::SEEK_CUR)
  61.         w, h = f.read(8).unpack('NN')
  62.       end
  63.     end
  64.     return w, h
  65.   end
  66.  
  67.   def self.get_jpg_wh(filename)
  68.     w = h = 0
  69.     File.open(filename, 'rb') do |f|
  70.       if f.read(2) == "\xFF\xD8"
  71.         sof0 = "\xFF\xC0"
  72.         while (buf = f.read(2)) != sof0
  73.           size = f.read(2).unpack('n')
  74.           f.seek(size - 2, IO::SEEK_CUR)
  75.         end
  76.         f.seek(3, IO::SEEK_CUR)
  77.         h, w = f.read(4).unpack('nn')
  78.       end
  79.     end
  80.     return w, h
  81.   end
  82. end
  83.  
  84.  
  85. class Bitmap
  86.   def to_int
  87.     self.__id__
  88.   end
  89.  
  90.   def save_jpg(filename, channels = 3, quality = 90)
  91.     ImageEx::Save_JPG.call(filename, self, channels, quality)
  92.   end
  93.  
  94.   def save_png(filename, channels = 4)
  95.     ImageEx::Save_PNG.call(filename, self, channels)
  96.   end
  97.  
  98.   # 读取图片至位图,主要是同样大小的单帧静态图片的动画,避免重复新建Bitmap  
  99.   def load_jpg(filename)
  100.     ImageEx::Load_JPG.call(filename, self)
  101.   end
  102.  
  103.   def load_png(filename)
  104.     ImageEx::Load_PNG.call(filename, self)
  105.   end   
  106. end
  107.  
  108. # GifSprite/WebpSprite并没打算复用,用完就释放掉,再新建
  109. class GifSprite < Sprite
  110.  
  111.   def initialize(filename, mode = 0, loop_count = 0, viewport = nil)
  112.  
  113.     w = h = 0
  114.     File.open(filename, "rb") do |f|
  115.       if (f.read(6) =~ /GIF8[79]a/)
  116.         w, h = f.read(4).unpack('SS')
  117.       end
  118.     end
  119.  
  120.     if w == 0 || h == 0
  121.       raise "#{self.class} ERR: #{filename} 可能不是 gif 图片"
  122.     end
  123.  
  124.     super(viewport)
  125.  
  126.     self.bitmap = Bitmap.new(w, h)
  127.     self.instance_eval do
  128.       def bitmap=(obj)
  129.       end
  130.     end
  131.  
  132.     self.bitmap.instance_eval do
  133.       alias :dispose_ori :dispose
  134.       def dispose(tag = 0)
  135.         dispose_ori if tag == ImageEx::GIF
  136.       end
  137.     end
  138.  
  139.     @cell = "\0" * ImageEx::GIF_CELL_SIZE
  140.     err = ImageEx::Show_GIF.call(filename, self.__id__, @cell.__id__,
  141.       mode, loop_count)
  142.  
  143.     case err
  144.     when -1   then raise "#{self.class} ERR: 打开 #{filename} 文件失败"
  145.     when -2   then raise "#{self.class} ERR: 位图 与 #{filename} 不符"
  146.     when -3   then raise "#{self.class} ERR: @cell 参数不符合要求"
  147.     when -100 then raise "#{self.class} ERR: 解析 #{filename} 失败"
  148.     when -101 then raise "#{self.class} ERR: 内存不足"
  149.     end
  150.  
  151.     @cell_ptr = [@cell].pack('p').unpack('L')[0]
  152.     @cell.freeze
  153.  
  154.     @use_thread = (mode & 0xF0 != 0) && (err != -99)
  155.     @delay = 0
  156.     @loop_over = false
  157.   end
  158.  
  159.   def over?
  160.     return @loop_over if @use_thread == false
  161.     i, c = @cell.unpack('@16LL')
  162.     return c != 0 && i >= c
  163.   end
  164.  
  165.   def update_frame
  166.     return if (@loop_over | @use_thread) == true
  167.     return if (self.disposed? | self.bitmap.disposed?) == true
  168.     return if self.visible == false || self.opacity == 0
  169.  
  170.     if @delay > 0
  171.       @delay -= 1
  172.     else
  173.       ms = ImageEx::Draw_GIF.call(@cell_ptr)
  174.       if ms < 0
  175.         @loop_over = true
  176.       else
  177.         @delay = (ms * Graphics.frame_rate + 999) / 1000
  178.       end
  179.     end
  180.   end
  181.  
  182.   def dispose
  183.     return if self.disposed? == true
  184.     ImageEx::Free_GIF.call(@cell_ptr)
  185.     self.bitmap.dispose(ImageEx::GIF)
  186.     super
  187.   end
  188. end
  189.  
  190.  
  191. class WebpSprite < Sprite
  192.  
  193.   def initialize(filename, mode = 0, loop_count = 0, viewport = nil)
  194.  
  195.     w = h = 0
  196.     File.open(filename, "rb") do |f|
  197.       if (f.read(4) == "RIFF")
  198.         f.seek(4, IO::SEEK_CUR)
  199.  
  200.         if (f.read(4) == "WEBP")        
  201.           chunk = f.read(4)
  202.           f.seek(4, IO::SEEK_CUR)
  203.  
  204.           if (chunk == "VP8 ")
  205.             if (f.read(1).unpack('C')[0][0] == 0)
  206.               f.seek(2, IO::SEEK_CUR)
  207.               if (f.read(3) == "\x9D\x01\x2A")
  208.                 w, h = f.read(4).unpack('SS')
  209.               end
  210.             end
  211.           elsif (chunk == "VP8L")
  212.             f.seek(1, IO::SEEK_CUR)
  213.             n = f.read(4).unpack('L')[0]
  214.  
  215.             w = (n & 0x3FFF) + 1
  216.             h = ((n & 0xFFFC000) >> 14) + 1
  217.           elsif (chunk == "VP8X")
  218.             f.seek(4, IO::SEEK_CUR)
  219.  
  220.             w, w16, h, h16 = f.read(6).unpack('SCSC')
  221.             w += (w16 << 16) + 1
  222.             h += (h16 << 16) + 1         
  223.           end
  224.         end
  225.       end
  226.     end
  227.  
  228.     if w == 0 || h == 0
  229.       raise "#{self.class} ERR: #{filename} 可能不是 webp 图片"
  230.     end
  231.  
  232.     super(viewport)
  233.  
  234.     self.bitmap = Bitmap.new(w, h)
  235.     self.instance_eval do
  236.       def bitmap=(obj)
  237.       end
  238.     end
  239.  
  240.     self.bitmap.instance_eval do
  241.       alias :dispose_ori :dispose
  242.       def dispose(tag = 0)
  243.         dispose_ori if tag == ImageEx::WEBP
  244.       end
  245.     end
  246.  
  247.     @cell = "\0" * ImageEx::WEBP_CELL_SIZE
  248.     err = ImageEx::Show_WEBP.call(filename, self.__id__, @cell.__id__,
  249.       mode, loop_count)
  250.  
  251.     case err
  252.     when -1   then raise "#{self.class} ERR: 打开 #{filename} 文件失败"
  253.     when -2   then raise "#{self.class} ERR: 位图 与 #{filename} 不符"
  254.     when -3   then raise "#{self.class} ERR: @cell 参数不符合要求"
  255.     when -100 then raise "#{self.class} ERR: 解析 #{filename} 失败"
  256.     when -101 then raise "#{self.class} ERR: 内存不足"
  257.     end
  258.  
  259.     @cell_ptr = [@cell].pack('p').unpack('L')[0]
  260.     @cell.freeze
  261.  
  262.     @use_thread = (mode != 0) && (err != -99)
  263.     @delay = 0
  264.     @loop_over = false
  265.   end
  266.  
  267.   def update_frame
  268.     return if (@loop_over | @use_thread) == true
  269.     return if (self.disposed? | self.bitmap.disposed?) == true
  270.     return if self.visible == false || self.opacity == 0
  271.  
  272.     if @delay > 0
  273.       @delay -= 1
  274.     else
  275.       ms = ImageEx::Draw_WEBP.call(@cell_ptr)
  276.       if ms < 0
  277.         @loop_over = true
  278.       else
  279.         @delay = (ms * Graphics.frame_rate + 999) / 1000
  280.       end
  281.     end
  282.   end
  283.  
  284.   def dispose
  285.     return if self.disposed? == true
  286.     ImageEx::Free_WEBP.call(@cell_ptr)
  287.     self.bitmap.dispose(ImageEx::WEBP)
  288.     super
  289.   end
  290. end


PS:示意图中的gif图片来自网络。
       修复DLL中有关gif的一个bug。该脚本中关于线程模式瞎写的,不好用,不推荐。
       自己写脚本喜欢越简单越好,使用脚本喜欢越全面越好,从使用角度说,这脚本很糟糕,所以就不写使用示例了。
       至于抠除黑色的计算,以前发的帖子写过 Bitmap#remove_black!

temp.png (288.28 KB, 下载次数: 14)

temp.png

ImageEx_rmxp.zip

282.67 KB, 下载次数: 11

ImageEx_rmxp.dll

点评

技能公共事件加你这个效果还不美翻了  发表于 2022-11-29 18:39

评分

参与人数 1星屑 +600 收起 理由
fux2 + 600 精品文章

查看全部评分

Lv5.捕梦者 (管理员)

老黄鸡

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

开拓者贵宾

2
发表于 2022-11-29 18:55:26 | 只看该作者
好东西,但我觉得塞一点使用说明更好
列出功能一览方便一些作者直接使用而不用去仔细看一遍内容
RGDirect - DirectX驱动的RGSS,点我了解.
RM全系列成套系统定制请联系QQ1213237796
不接受对其他插件维护的委托
回复 支持 反对

使用道具 举报

Lv5.捕梦者 (版主)

梦石
1
星屑
23999
在线时间
3339 小时
注册时间
2011-7-8
帖子
3926

开拓者

3
发表于 2022-11-29 19:04:19 | 只看该作者
挺好的,gif和webp这种有序列帧的格式,就应该直接动画播放出来嘛
熟悉rgss和ruby,xp区版主~
正在填坑:《膜拜组传奇》讲述膜拜组和学霸们的故事。
已上steam:与TXBD合作的Reformers《变革者》
* 战斗调用公共事件 *
* RGSOS 网络脚本 *
回复 支持 反对

使用道具 举报

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

本版积分规则

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

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

GMT+8, 2024-11-27 12:30

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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