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

Project1

 找回密码
 注册会员
搜索
Project1 查看内容

GIF图片播放

2007-6-15 00:00| 发布者: 叶舞枫| 查看: 9108| 评论: 0|原作者: 前技术区版大·灼眼的夏娜

摘要:     作者 灼眼的夏娜 版本 没有 相关网址 点此进入讨论贴 范例工程 点击下载范例工程   脚本内容  =begin   脚本:【怨念产物 - GIF图片播放】    功能:在
 
 

作者

灼眼的夏娜

版本

没有

相关网址

点此进入讨论贴

范例工程

点击下载范例工程


 

脚本内容

 =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
 
  #-------------------------------------------------------------

1

鲜花

刚表态过的朋友 (1 人)

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