ImageEx:感觉很鸡肋,电脑里扔了2个多月,毕竟都写了,发贴混点经验。
ImageEx_rmxp.dll VS2015 C++语言编写(因为有库是C++的,其实都是按C写的)。
RUBY 代码
[code]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)
# 这两个方法其实没什么用……
defself.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
defself.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_evaldo
def bitmap=(obj)
end
end
self.bitmap.instance_evaldo
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 thenraise"#{self.class} ERR: 打开 #{filename} 文件失败"
when-2 thenraise"#{self.class} ERR: 位图 与 #{filename} 不符"
when-3 thenraise"#{self.class} ERR: @cell 参数不符合要求"
when-100thenraise"#{self.class} ERR: 解析 #{filename} 失败"
when-101thenraise"#{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_overif@use_thread == false
i, c = @cell.unpack('@16LL')
return c != 0 && i >= c
end
def update_frame
returnif(@loop_over | @use_thread) == true
returnif(self.disposed? | self.bitmap.disposed?) == true
returnifself.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
returnifself.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