=begin 脚本:【怨念产物 - GIF图片播放】 功能:在游戏中播放GIF图片 ※ 表情优先。 说明: 使用步骤: 1、使用 @gs = GIFSprite.new([viewport,[x,[,y,[loop_counts]]]]) 创建GIF图片对象; 2、然后使用 @gs.bitmap = "gif_filename" ※ 包含文件夹路径; 3、可以 @gs.loop_counts = n 设置循环次数,-1表示无限循环(默认的),0就释放图片。 4、@gs.x = x,@gs.y = y,@gs.z = z 等设置各种坐标值。 补充:1、由于考虑的效率问题,提供了生成临时文件技术,即第一运行之后以后每次运 行会直接读取临时文件生成对象,可以使用 GIFSprite.TmpFileclear 清空临时 文件。 2、可以褂?GIFSprite.pre_load(filename_arr) 数组预加载一组图片。 版本:v1.0 作者:灼眼的夏娜 =end #============================================================================== # ■ System #------------------------------------------------------------------------------ # 处理系统相关的模块 。 #============================================================================== module System #-------------------------------------------------------------------------- # ● 模块函数 #-------------------------------------------------------------------------- module_function #-------------------------------------------------------------------------- # ● API函数声明 #-------------------------------------------------------------------------- WinExec = Win32API.new("kernel32","WinExec",'pi','i') #-------------------------------------------------------------------------- # ● 查看或修改文件及文件夹属性 # filename :文件或文件夹名字 # # +a -a :添加、删除 存档 属性 # +r -r :添加、删除 只读 属性 # +s -s :添加、删除 系统 属性 # +h -h :添加、删除 隐藏 属性 #-------------------------------------------------------------------------- def attrib(filename,*args) if args.empty? astr = `attrib #{filename}` attri_arr = Array.new astr = astr.split(/:/)[0] astr = astr[0,astr.size - 1] astr.gsub!(/ /,"") return astr.split(//) else cmdline = "" for cmdchar in args cmdchar.downcase! next if cmdline.include? cmdchar if ["+a","-a","+r","-r","+s","-s","+h","-h"].include? cmdchar cmdline += " " + cmdchar end end cmdline += " " result = WinExec.call("attrib #{cmdline}#{filename}",0) if result < 31 return end end end end #============================================================================== # ■ GIF #------------------------------------------------------------------------------ # 分析处理GIF图片的核心模块 。 #============================================================================== module GIF # 定义常量 SIZE_GIFH = 6 SIZE_GIFS = 7 SIZE_GIFI = 9 SIZE_GIFC = 6 SIZE_GIFP = 13 SIZE_GIFA = 12 CODE_MASK = [0x0000, 0x0001,0x0003,0x0007,0x000f, 0x001f,0x003f,0x007f,0x00ff, 0x01ff,0x03ff,0x07ff,0x0fff] INC_TABLE = [8,8,4,2,0] BGN_TABLE = [0,4,2,1,0] # 建立文件夹 Dir.mkdir("GIF") unless Dir["*"].include?("GIF") # 函数定义 module_function #-------------------------------------------------------------------------- # ● 分解gif图片 #-------------------------------------------------------------------------- def analyze_gif @old_dir = Dir.pwd Dir.chdir("GIF") @total_gif = [] for g in Dir["*"] suf = g.split(/\./) if suf[1].is_a?(String) and suf[1].downcase == "gif" @total_gif.push(g) Dir.mkdir(suf[0]) unless Dir["*"].include? suf[0] end end @total_gif.each{|file| self.readdata(file)} Dir.chdir(@old_dir) p '全部分解完毕,点击确定退出' exit end #-------------------------------------------------------------------------- # ● 读取文件数据:成功返回@gif_infos,失败返回nil #-------------------------------------------------------------------------- def readdata(filename) # 检查是否有临时记忆文件 tmp_filename = File.basename(filename,".*") unless Dir["~TEMP/#{tmp_filename}_infos.fmd"].empty? begin giffr = open("~TEMP/#{tmp_filename}_infos.fmd","rb") tmp_infos = Marshal.load(giffr) giffr.close if Dir["~TEMP/#{tmp_filename}_*.png"].size == tmp_infos.total_frames return tmp_infos end rescue end end # 初始化数据 self.initial_var(filename) # 打开文件 begin @f = open(filename,"rb") # 读取文件头 self.read_gifh # 读取逻辑屏幕描述块 self.read_gifs # 读取下一个字节 @temp = @f.read(1)[0] # 循环读取每个图象描述块 while true if @temp == 0x2c # 读取图象描述块 self.read_gifi end if @temp == 0x21 # 读取图象扩展块 self.read_gife end if @temp == 0x3b break end # 读取下一个字节 @temp = @f.read(1)[0] end # ※ 设置图象帧数 @gif_infos.total_frames = @frame_count # ※ 写入图象分解数据 giffw = open("~TEMP/#{@filename}_infos.fmd","wb") Marshal.dump(@gif_infos,giffw) giffw.close rescue return nil ensure @f.close end return @gif_infos end #-------------------------------------------------------------------------- # ● 初始化变量 #-------------------------------------------------------------------------- def initial_var(filename) # ※ 生成图象数据对象 @gif_infos = GIFSprite::Infos.new # 帧数计数 @frame_count = 0 @f = nil @temp = nil # 获取文件名 @filename = File.basename(filename,".*") end #-------------------------------------------------------------------------- # ● 读取文件头 #-------------------------------------------------------------------------- def read_gifh @gifh = @f.read(SIZE_GIFH) if @gifh[0,3] != "GIF" raise "不是GIF文件!" end if @gifh[3,3] != "87a" and @gifh[3,3] != "89a" raise "不支持的版本!" end end #-------------------------------------------------------------------------- # ● 读取逻辑屏幕描述块 #-------------------------------------------------------------------------- def read_gifs @gifs = @f.read(SIZE_GIFS).unpack("S2C3") # 获取调色板位数 @_pal_bits = (@gifs[2] & 7) + 1 # ※ 获取图象宽度 @gif_infos.width = @gifs[0] # ※ 获取图象高度 @gif_infos.height = @gifs[1] # 是否有全局调色板 if @gifs[2] >> 7 == 1 # 全局调色板大小 @g_pal_size = 3 * (1 << @_pal_bits) # 读取全局调色板数据 @g_pal = @f.read(@g_pal_size).unpack("C*") end end #-------------------------------------------------------------------------- # ● 读取图象描述块 #-------------------------------------------------------------------------- def read_gifi # 读取图象描述块 @gifi = @f.read(SIZE_GIFI).unpack("S4C") # ※ 生成临时帧数据对象 @gif_fd = GIFSprite::Infos::FrameData.new if @gif_fd.nil? # ※ 获取帧偏移 @gif_fd.offset_x = @gifi[0] @gif_fd.offset_y = @gifi[1] # 获取宽度和高度 @_width = @gifi[2] @_height = @gifi[3] # 清空局部调色板 @l_pal = nil # 是否有局部调色板 if @gifi[4] >> 7 == 1 # 获取调色板位数 @_pal_bits = (@gifi[4] & 7) + 1 # 局部调色板大小 @l_pal_size = 3 * (1 << @_pal_bits) # 读取局部调色板数据 @l_pal = @f.read(@l_pal_size).unpack("C*") end # 获取交错标记 @_lace = (@gifi[4] >> 6) & 1 # 修正调色板位数 @_pal_bits = @_pal_bits == 1 ? 1 : (@_pal_bits <= 4 ? 4 : 8) # 获取行字节数 @_width_bytes = (((@_width * @_pal_bits) + 31) >> 5) << 2 # 读取图象压缩数据 self.read_lzw_data # ※ 设置GIF帧数据 @gif_infos.frame_data[@frame_count - 1] = @gif_fd # ※ 清除帧数据 @gif_fd = nil end #-------------------------------------------------------------------------- # ● 读取图象压缩数据 #-------------------------------------------------------------------------- def read_lzw_data # 解码用 lzw_mincodelen = @f.read(1)[0] # 帧数加 1 @frame_count += 1 # 图象块数据 image_data = "" # 块大小 blocksize = @f.read(1)[0] while blocksize > 0 image_data += @f.read(blocksize) blocksize = @f.read(1)[0] end # 导出图象 self.dump_imgs(image_data,lzw_mincodelen) end #-------------------------------------------------------------------------- # ● 读取扩充块 #-------------------------------------------------------------------------- def read_gife label = @f.read(1)[0] case label when 0xf9 # 图形控制扩展块 @gifc = @f.read(SIZE_GIFC).unpack("C2SC2") # ※ 生成帧数据对象 @gif_fd = GIFSprite::Infos::FrameData.new # ※ 获取帧数据 延迟时间 @gif_fd.delay_time = @gifc[2] # ※ 获取下一帧的处理方法 @gif_fd.disposal_method = (@gifc[1] & 28) >> 2 # 获取透明颜色 @_trans_index = nil if @gifc[1] & 1 > 0 @_trans_index = @gifc[3] end when 0x01 # 图形说明扩展块 @gifp = @f.read(SIZE_GIFP).unpack("CS4C4") blocksize = @f.read(1)[0] while blocksize > 0 @f.read(blocksize) blocksize = @f.read(1)[0] end when 0xfe # 注解说明扩展块 blocksize = @f.read(1)[0] while blocksize > 0 @f.read(blocksize) blocksize = @f.read(1)[0] end when 0xff # 应用程序扩展块 @gifa = @f.read(SIZE_GIFA).unpack("C*") blocksize = @f.read(1)[0] while blocksize > 0 @f.read(blocksize) blocksize = @f.read(1)[0] end end end #-------------------------------------------------------------------------- # ● 设置调色板 #-------------------------------------------------------------------------- def set_pal @_pal = [] if @l_pal != nil @_pal = @l_pal elsif @g_pal != nil @_pal = @g_pal else for i in 0...1 << @_pal_bits @_pal.push i,i,i end end end #-------------------------------------------------------------------------- # ● 解码图形数据 #-------------------------------------------------------------------------- def dump_imgs(image_data,lze_len) @image_data = image_data.unpack("C*") self.set_pal @png_data = [] @stack = [] @images = [] @prefix = [] @suffix = [] @bitcount = @_pal_bits @widthcount = 0 @left_bits = 0x00 @current_bits = lze_len + 0x01 @lzw_clear = 1 << lze_len @lzw_eoi = @lzw_clear + 1 @nowtablendx = @lzw_clear + 2 @toptablendx = 1 << @current_bits @wdata = 0 @wcode = 0 @oldcode = 0xffff @row_num = 0 @tempchar = 0x00 @pass = 0x00 @firstchar = 0 @tempndx = 0 # 读取编码字符 self.read_byte # 不是@lzw_eoi则循环 while @wcode != @lzw_eoi # @lzw_clear码 if @wcode == @lzw_clear for i in 0...@lzw_clear @prefix[i] = 0xffff @suffix[i] = i end for i in @nowtablendx...4096 @prefix[i] = 0xffff @suffix[i] = 0x00 end @current_bits = lze_len + 0x01 @nowtablendx = @lzw_clear + 2 @toptablendx = 1 << @current_bits @oldcode = 0xffff # 读取编码字符 self.read_byte if @wcode != @lzw_eoi while @prefix[@wcode] != 0xffff @stack.push(@suffix[@wcode]) @wcode = @prefix[@wcode] end @stack.push(@suffix[@wcode]) @firstchar = @stack[-1] # 输出解码数据 self.output_data end else if @wcode < @nowtablendx @tempndx = @wcode else @tempndx = @oldcode @stack.push(@firstchar) end while @prefix[@tempndx] != 0xffff @stack.push(@suffix[@tempndx]) @tempndx = @prefix[@tempndx] end @stack.push(@suffix[@tempndx]) @firstchar = @stack[-1] @prefix[@nowtablendx] = @oldcode @suffix[@nowtablendx] = @firstchar @nowtablendx += 1 if @nowtablendx == @toptablendx and @current_bits < 12 @current_bits += 1 @toptablendx = 1 << @current_bits end # 输出解码数据 self.output_data end @oldcode = @wcode # 读取编码字符 self.read_byte end Graphics.update # 生成png图 self.make_png end #-------------------------------------------------------------------------- # ● 读取下一个字节 #-------------------------------------------------------------------------- def read_byte while @left_bits < @current_bits @next_char = @image_data.shift @wdata |= (@next_char << @left_bits) @left_bits += 0x08 end @wcode = @wdata & CODE_MASK[@current_bits] @wdata >>= @current_bits @left_bits -= @current_bits end #-------------------------------------------------------------------------- # ● 输出解码数据 #-------------------------------------------------------------------------- def output_data while [email protected]? @tempchar |= (@stack.pop << (8 - @bitcount)) if @bitcount == 8 @images.push(@tempchar) @tempchar = 0x00 @bitcount = @_pal_bits else @bitcount += @_pal_bits end @widthcount += 1 if @widthcount == @_width if @bitcount != @_pal_bits @images.push(@tempchar) @tempchar = 0x00 @bitcount = @_pal_bits end @png_data[@row_num] = @images.clone @images.clear if @_lace > 0 @row_num += INC_TABLE[@pass] if @row_num >= @_height @pass += 1 @row_num = BGN_TABLE[@pass] end else @row_num += 1 end @widthcount = 0 end end end #-------------------------------------------------------------------------- # ● 生成png图片 #-------------------------------------------------------------------------- def make_png fp = open("~TEMP/#@filename" + sprintf("_%02d",@frame_count)+".png","wb") fp.write(self.make_png_header) fp.write(self.make_png_ihdr) fp.write(self.make_png_plte) if @_trans_index.nil? fp.write(self.make_png_idat) fp.write(self.make_png_iend) fp.close end #-------------------------------------------------------------------------- # ● png头文件 #-------------------------------------------------------------------------- def make_png_header return [0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a].pack("C*") end #-------------------------------------------------------------------------- # ● png信息头块 #-------------------------------------------------------------------------- def make_png_ihdr ih_size = [13].pack("N") ih_sign = "IHDR" ih_width = [@_width].pack("N") ih_height = [@_height].pack("N") if @_trans_index != nil ih_bit_depth = [@_pal_bits > 8 ? 16 : 8].pack("C") ih_color_type = [6].pack("C") else ih_bit_depth = [@_pal_bits].pack("C") ih_color_type = [3].pack("C") end ih_compression_method = [0].pack("C") ih_filter_method = [0].pack("C") ih_interlace_method = [0].pack("C") string = ih_sign + ih_width + ih_height + ih_bit_depth + ih_color_type + ih_compression_method + ih_filter_method + ih_interlace_method ih_crc = [Zlib.crc32(string)].pack("N") return ih_size + string + ih_crc end #-------------------------------------------------------------------------- # ● png调色板块 #-------------------------------------------------------------------------- def make_png_plte pl_size = [@_pal.size].pack("N") pl_sign = "PLTE" pl_data = @_pal.pack("C*") pl_crc = [Zlib.crc32(pl_sign + pl_data)].pack("N") return pl_size + pl_sign + pl_data + pl_crc end #-------------------------------------------------------------------------- # ● png数据块 #-------------------------------------------------------------------------- def make_png_idat lz_data = [] if @_trans_index != nil for i in 0...@png_data.size lz_data.push 0 for j in @png_data[i] if j == @_trans_index lz_data.push @_pal[j*3],@_pal[j*3+1],@_pal[j*3+2],0 else lz_data.push @_pal[j*3],@_pal[j*3+1],@_pal[j*3+2],255 end end end else for i in 0...@png_data.size lz_data.push 0 lz_data += @png_data[i] end end id_data = Zlib::Deflate.deflate(lz_data.pack("C*"),9) id_size = [id_data.size].pack("N") id_sign = "IDAT" id_crc = [Zlib.crc32(id_sign + id_data)].pack("N") return id_size + id_sign + id_data + id_crc end #-------------------------------------------------------------------------- # ● png 结尾块 #-------------------------------------------------------------------------- def make_png_iend ie_size = [0].pack("N") ie_sign = "IEND" ie_crc = [Zlib.crc32(ie_sign)].pack("N") return ie_size + ie_sign + ie_crc end end #============================================================================== # ■ Graphics #------------------------------------------------------------------------------ # 处理画面的模块 。 #============================================================================== class << Graphics #-------------------------------------------------------------------------- # ● 添加别名、线程、临界区 #-------------------------------------------------------------------------- unless method_defined? :origin_update alias origin_update update def update_critical Thread.critical = true origin_update Thread.critical = false end Thread.new{loop{Graphics.update_critical;sleep(9)}} end #-------------------------------------------------------------------------- # ● 定义类变量 #-------------------------------------------------------------------------- @@gif_sprites = Array.new #------------------------------------------------------------- |