赞 | 68 |
VIP | 0 |
好人卡 | 0 |
积分 | 65 |
经验 | 0 |
最后登录 | 2023-7-2 |
在线时间 | 119 小时 |
Lv4.逐梦者
- 梦石
- 0
- 星屑
- 6483
- 在线时间
- 119 小时
- 注册时间
- 2020-1-8
- 帖子
- 234
|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
本帖最后由 RPGzh500223 于 2022-11-30 14:57 编辑
感觉很鸡肋,电脑里扔了2个多月,毕竟都写了,发贴混点经验。
ImageEx_rmxp.dll VS2015 C++语言编写(因为有库是C++的,其实都是按C写的)。
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
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
PS:示意图中的gif图片来自网络。
修复DLL中有关gif的一个bug。该脚本中关于线程模式瞎写的,不好用,不推荐。
自己写脚本喜欢越简单越好,使用脚本喜欢越全面越好,从使用角度说,这脚本很糟糕,所以就不写使用示例了。
至于抠除黑色的计算,以前发的帖子写过 Bitmap#remove_black! |
评分
-
查看全部评分
|