module ImageEx dll = "ImageEx_rmxp.dll" # ———— png 与 jpeg —————————————————— # 仅支持 jpeg(Gray/RGB)、png(Gray/GrayAlpha/RGB/RGBA) # 使用libjpeg/libpng # ———————————————————————————— # 支持的模式会转换至BGRA,不支持的模式会返回-1。 # filename_uft8, bitmap_obj_id Load_JPG = Win32API.new(dll, 'bitmap_load_jpg', 'PL', 'L') # filename_utf8, bitmap_obj_id # channels 1或3 BGRA会转换至支持的对应模式 # quality 0..100 质量越好,文件越大 Save_JPG = Win32API.new(dll, 'bitmap_save_to_jpg', 'PLLL', 'L') # 支持的模式会转换至BGRA,不支持的模式无效操作。 # filename_uft8, bitmap_obj_id Load_PNG = Win32API.new(dll, 'bitmap_load_png', 'PL', 'L') # filename_utf8, bitmap_obj_id # channels 1..4 BGRA会转换至支持的对应模式 Save_PNG = Win32API.new(dll, 'bitmap_save_to_png', 'PLL', 'L') # ———— gif 与 webp —————————————————————————— # 仅支持读取,无论是否使用线程(Win32 CreateThread)都需要释放(调用dispose) # gif中disposal_method不支持DISPOSE_PREVIOUS # 播放效果视文件而定,可能会“画面闪烁” # 效率:非线程模式,640*480大小,读取一帧 gif:1000次/秒 webp:300次/秒 # 参照,640*480大小的Bitmap#blt 260+次/秒 # 使用libgif/libwebp # ———————————————————————————————————— # filename_utf8 : utf8编码的文件名。 # sprite_obj_id : RMXP 精灵(Sprite) 对象的 object_id,精灵需设置好其位图。 # gif_cell_string : GIF_CELL_SIZE字节的字符串,用来保存一些数据。 # play_mode : 0..3位 是否抠图。抠图效果不错,对效率影响不大。 # 1:抠除黑色;2:抠除白色;其他(0/3):原图。 # 4..7位 是否线程模式。 0:不使用;非0:使用。 # loop_count : 自定义播放次数。 0:文件默认次数;负数:一直播放;正数:指定次数。 Show_GIF = Win32API.new(dll, 'show_gif', 'PLPLL', 'L') Draw_GIF = Win32API.new(dll, 'draw_gif', 'L', 'L') Free_GIF = Win32API.new(dll, 'free_gif', 'L', 'L') GIF = 0x666967 GIF_CELL_SIZE = Show_GIF.call(nil, 0, 0, 0, 0) # 参数四 mode : 是否线程模式。 0:不使用;非0:使用。 # 其余参数,参见Show_GIF Show_WEBP = Win32API.new(dll, 'show_webp', 'PLPLL', 'L') Draw_WEBP = Win32API.new(dll, 'draw_webp', 'L', 'L') Free_WEBP = Win32API.new(dll, 'free_webp', 'L', 'L') WEBP = 0x70626577 WEBP_CELL_SIZE = Show_WEBP.call(nil, 0, 0, 0, 0) # 这两个方法其实没什么用…… def self.get_png_wh(filename) w = h = 0 File.open(filename, 'rb') do |f| if f.read(8) == "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A" f.seek(8, IO::SEEK_CUR) w, h = f.read(8).unpack('NN') end end return w, h end def self.get_jpg_wh(filename) w = h = 0 File.open(filename, 'rb') do |f| if f.read(2) == "\xFF\xD8" sof0 = "\xFF\xC0" while (buf = f.read(2)) != sof0 size = f.read(2).unpack('n') f.seek(size - 2, IO::SEEK_CUR) end f.seek(3, IO::SEEK_CUR) h, w = f.read(4).unpack('nn') end end return w, h end end class Bitmap def to_int self.__id__ end def save_jpg(filename, channels = 3, quality = 90) ImageEx::Save_JPG.call(filename, self, channels, quality) end def save_png(filename, channels = 4) ImageEx::Save_PNG.call(filename, self, channels) end # 读取图片至位图,主要是同样大小的单帧静态图片的动画,避免重复新建Bitmap def load_jpg(filename) ImageEx::Load_JPG.call(filename, self) end def load_png(filename) ImageEx::Load_PNG.call(filename, self) end end # GifSprite/WebpSprite并没打算复用,用完就释放掉,再新建 class GifSprite < Sprite def initialize(filename, mode = 0, loop_count = 0, viewport = nil) w = h = 0 File.open(filename, "rb") do |f| if (f.read(6) =~ /GIF8[79]a/) w, h = f.read(4).unpack('SS') end end if w == 0 || h == 0 raise "#{self.class} ERR: #{filename} 可能不是 gif 图片" end super(viewport) self.bitmap = Bitmap.new(w, h) self.instance_eval do def bitmap=(obj) end end self.bitmap.instance_eval do alias :dispose_ori :dispose def dispose(tag = 0) dispose_ori if tag == ImageEx::GIF end end @cell = "\0" * ImageEx::GIF_CELL_SIZE err = ImageEx::Show_GIF.call(filename, self.__id__, @cell.__id__, mode, loop_count) case err when -1 then raise "#{self.class} ERR: 打开 #{filename} 文件失败" when -2 then raise "#{self.class} ERR: 位图 与 #{filename} 不符" when -3 then raise "#{self.class} ERR: @cell 参数不符合要求" when -100 then raise "#{self.class} ERR: 解析 #{filename} 失败" when -101 then raise "#{self.class} ERR: 内存不足" end @cell_ptr = [@cell].pack('p').unpack('L')[0] @cell.freeze @use_thread = (mode & 0xF0 != 0) && (err != -99) @delay = 0 @loop_over = false end def over? return @loop_over if @use_thread == false i, c = @cell.unpack('@16LL') return c != 0 && i >= c end def update_frame return if (@loop_over | @use_thread) == true return if (self.disposed? | self.bitmap.disposed?) == true return if self.visible == false || self.opacity == 0 if @delay > 0 @delay -= 1 else ms = ImageEx::Draw_GIF.call(@cell_ptr) if ms < 0 @loop_over = true else @delay = (ms * Graphics.frame_rate + 999) / 1000 end end end def dispose return if self.disposed? == true ImageEx::Free_GIF.call(@cell_ptr) self.bitmap.dispose(ImageEx::GIF) super end end class WebpSprite < Sprite def initialize(filename, mode = 0, loop_count = 0, viewport = nil) w = h = 0 File.open(filename, "rb") do |f| if (f.read(4) == "RIFF") f.seek(4, IO::SEEK_CUR) if (f.read(4) == "WEBP") chunk = f.read(4) f.seek(4, IO::SEEK_CUR) if (chunk == "VP8 ") if (f.read(1).unpack('C')[0][0] == 0) f.seek(2, IO::SEEK_CUR) if (f.read(3) == "\x9D\x01\x2A") w, h = f.read(4).unpack('SS') end end elsif (chunk == "VP8L") f.seek(1, IO::SEEK_CUR) n = f.read(4).unpack('L')[0] w = (n & 0x3FFF) + 1 h = ((n & 0xFFFC000) >> 14) + 1 elsif (chunk == "VP8X") f.seek(4, IO::SEEK_CUR) w, w16, h, h16 = f.read(6).unpack('SCSC') w += (w16 << 16) + 1 h += (h16 << 16) + 1 end end end end if w == 0 || h == 0 raise "#{self.class} ERR: #{filename} 可能不是 webp 图片" end super(viewport) self.bitmap = Bitmap.new(w, h) self.instance_eval do def bitmap=(obj) end end self.bitmap.instance_eval do alias :dispose_ori :dispose def dispose(tag = 0) dispose_ori if tag == ImageEx::WEBP end end @cell = "\0" * ImageEx::WEBP_CELL_SIZE err = ImageEx::Show_WEBP.call(filename, self.__id__, @cell.__id__, mode, loop_count) case err when -1 then raise "#{self.class} ERR: 打开 #{filename} 文件失败" when -2 then raise "#{self.class} ERR: 位图 与 #{filename} 不符" when -3 then raise "#{self.class} ERR: @cell 参数不符合要求" when -100 then raise "#{self.class} ERR: 解析 #{filename} 失败" when -101 then raise "#{self.class} ERR: 内存不足" end @cell_ptr = [@cell].pack('p').unpack('L')[0] @cell.freeze @use_thread = (mode != 0) && (err != -99) @delay = 0 @loop_over = false end def update_frame return if (@loop_over | @use_thread) == true return if (self.disposed? | self.bitmap.disposed?) == true return if self.visible == false || self.opacity == 0 if @delay > 0 @delay -= 1 else ms = ImageEx::Draw_WEBP.call(@cell_ptr) if ms < 0 @loop_over = true else @delay = (ms * Graphics.frame_rate + 999) / 1000 end end end def dispose return if self.disposed? == true ImageEx::Free_WEBP.call(@cell_ptr) self.bitmap.dispose(ImageEx::WEBP) super end end
temp.png (288.28 KB, 下载次数: 12)
282.67 KB, 下载次数: 11
ImageEx_rmxp.dll
欢迎光临 Project1 (https://rpg.blue/) | Powered by Discuz! X3.1 |