03-07-2008, 04:33 AM 
	
	
	Rataime's Image Save Files
Hi guys ! Nice to see some of you again !
After playing Master of the Wind, and not having opened RMXP for one year, I wanted to check if I was still able to make original scripts (with an heavy dose of eye-candy, obviously). Well, you tell me. I've coded this script in a few hours today, inspired by http://www.squidi.net/three/entry.php?id=12
This script allows you to save your game in .png (picture) files. That way, you can distribute, host and share them easily, for example as a forum signature. You can also use thumbnail views for quick sorting and browsing, given that you can put whatever information you want on the picture.
For example, the following pictures :
![[Image: Save1.png]](http://rataime.free.fr/rmxp/Demos/Save1.png) 
       ![[Image: Save3.png]](http://rataime.free.fr/rmxp/Demos/Save3.png)
are actual savegames of my demo. You can put them in my demo and load them in rmxp !
It's obviously up to you to configure how are generated the pictures, the ones above are just an example automatically using the battleback of the last map I was on.
The script needs the SDK, and can't be converted to non-SDK. Dealing with savefiles without the SDK is a sure way to mess with other scripts... Even now, it will still probably mess with non-SDK save scripts.
Here's the code :
 Content Hidden
  			Code:
#==============================================================================
# ** Image Save File
#------------------------------------------------------------------------------
# Rataime
# Version 1.0
# 11/08/2008 (2008-08-11)
# Original Idea : Squdi (http://www.squidi.net/three/entry.php?id=12)
#------------------------------------------------------------------------------
#
# This script allows you to save your game in .png (picture) files. That way,
# you can distribute and host them easily, for example as a forum signature.
# You can also use thumbnail views for quick sorting and browsing, given that
# you can put whatever innformation you want on the picture.
#
# The files will be saved as Save1.png, Save2.png... If both Save1.rxdata and
# Save1.png exist, Save1.png will be loaded.
#
# If for whatever reason you want your game to be able to load .png files but
# still saving as .rxdata, set IMAGE_SAVEFILE_SAVE_AS_PNG to false. I don't
# recommand it, as it will become complicated when there's both a Save1.rxdata 
# and Save1.png...
#
# To configure your own picture, see rataime_generate_png_file_from_template
#
#==============================================================================
#============================================================================== 
# IMAGE_SAVEFILE_SAVE_AS_PNG : Set to false to save as .rxdata
#==============================================================================
IMAGE_SAVEFILE_SAVE_AS_PNG = true
class Scene_Save < Scene_File
  
  #--------------------------------------------------------------------------
  # * rataime_generate_png_file_from_template
  #
  # This method generates the png file that will be use by the save file.
  # Do whatever you want here, the following code is just a demo
  # I've extended the Bitmap class a bit to include some common Window
  # methods like draw_actor_level. Feel free to experiment new ways of creating
  # the picture !
  #--------------------------------------------------------------------------
  
  def rataime_generate_png_file_from_template
    # We load Graphics\Pictures\save_template_demo.png to use as a background
    bitmap = RPG::Cache.picture('save_template_demo')
    
    # We draw the 4 actor graphics and their levels
    bitmap.draw_actor_graphic($game_party.actors[0],52,277)
    bitmap.draw_actor_level($game_party.actors[0], 73, 237)
    if $game_party.actors[1] != nil
      bitmap.draw_actor_graphic($game_party.actors[1],52,350)
      bitmap.draw_actor_level($game_party.actors[1], 73, 310)
      if $game_party.actors[2] != nil
        bitmap.draw_actor_graphic($game_party.actors[2],167,277)
        bitmap.draw_actor_level($game_party.actors[2], 188, 237)
        if $game_party.actors[3] != nil
          bitmap.draw_actor_graphic($game_party.actors[3],167,350)
          bitmap.draw_actor_level($game_party.actors[3], 188, 310)
        end
      end
    end
    
    # We draw the play time
    bitmap.draw_playtime(100,182)
    
    # We draw the battleback of the last map on our picture
    # The size is ajusted so the recatngle is filled without stretching
    # the battleback, by discarding the sides of the battleback
    battleback = RPG::Cache.battleback($game_map.battleback_name)
    from = Rect.new(42, 0, 556, 320)
    to = Rect.new(32, 49, 217, 125)
    bitmap.stretch_blt(to, battleback, from)
    
    return bitmap
  end
  
  alias rataime_image_save_file_on_decision on_decision
  def on_decision(filename)
    if IMAGE_SAVEFILE_SAVE_AS_PNG
      filename = filename.split('.')[0] + '.png'
    end
    rataime_image_save_file_on_decision(filename)
  end
  
  alias rataime_image_save_file_write_save_data write_save_data
    
  def write_save_data(file)
    if IMAGE_SAVEFILE_SAVE_AS_PNG
      rataime_generate_png_file_from_template.rataime_write_png(file)
    end
    rataime_image_save_file_write_save_data(file)
  end
  
end
class Scene_Load < Scene_File
  alias rataime_image_save_file_on_decision on_decision
  alias rataime_image_save_file_read_save_data read_save_data
  def on_decision(filename)
    @extension = filename.split('.')[-1].downcase
    rataime_image_save_file_on_decision(filename)
  end
  
  def read_save_data(file)
    if @extension.downcase == 'png'
      file.gets('IEND')
      4.times do
        file.getc
      end
    end
    rataime_image_save_file_read_save_data(file)
  end
  
end
class Scene_File
  
  alias rataime_image_save_file_make_filename make_filename
  def make_filename(file_index)
    if FileTest.exist?("Save#{file_index + 1}.png")
      return "Save#{file_index + 1}.png"
    else
      return "Save#{file_index + 1}.rxdata"
    end
  end
  
end
class Scene_Title
  
  alias rataime_image_save_file_main_test_continue main_test_continue
  def main_test_continue
    rataime_image_save_file_main_test_continue
    for i in 0..3
      if FileTest.exist?("Save#{i+1}.png")
        # Sets Continued Enable Flag On
        @continue_enabled = true
      end
    end
  end
end
class Window_SaveFile < Window_Base
  
  alias rataime_image_save_file_init_gamedata init_gamedata
  
  def init_gamedata
    if @filename.split('.')[-1].downcase == 'png'
      file = File.open(@filename, "rb")
      @time_stamp = file.mtime
      file.gets('IEND')
      4.times do
        file.getc
      end
      @characters = Marshal.load(file)
      @frame_count = Marshal.load(file)
      @game_system = Marshal.load(file)
      @game_switches = Marshal.load(file)
      @game_variables = Marshal.load(file)
      @total_sec = @frame_count / Graphics.frame_rate
      file.close
    else
      rataime_image_save_file_init_gamedata
    end
  end
end
#============================================================================== 
# ** Bitmap     
#==============================================================================
class Bitmap
  def normal_color
    return Color.new(255, 255, 255, 255)
  end
  
  def system_color
    return Color.new(192, 224, 255, 255)
  end
  
  def draw_actor_graphic(actor, x, y)
    bmp = RPG::Cache.character(actor.character_name, actor.character_hue)
    cw = bmp.width / 4
    ch = bmp.height / 4
    src_rect = Rect.new(0, 0, cw, ch)
    self.blt(x - cw / 2, y - ch, bmp, src_rect)
  end
  
  def draw_playtime(x,y)
    total_sec = Graphics.frame_count / Graphics.frame_rate
    hour = total_sec / 60 / 60
    min = total_sec / 60 % 60
    sec = total_sec % 60
    text = sprintf("%02d:%02d:%02d", hour, min, sec)
    self.font.color = normal_color
    self.draw_text(x, y, 120, 32, text, 2)
  end
  
  def draw_actor_level(actor, x, y)
    self.font.color = system_color
    self.draw_text(x, y, 32, 32, "Lv")
    self.font.color = normal_color
    self.draw_text(x + 24, y, 24, 32, actor.level.to_s, 2)
  end
  
  def rataime_write_png(f)
    Zlib::Png_File.open('temp.gz')   { |gz| gz.make_png(self, 0) }
    Zlib::GzipReader.open('temp.gz') { |gz| $read = gz.read }
    f.write($read)
    File.delete('temp.gz')
  end
end
#============================================================================== 
# ** Modules.Zlib
#------------------------------------------------------------------------------
# Description:
# ------------
# Adds PNG_File class to save Bitmap's to PNG Files
#  
# Class List:
# -----------
# Png_File
#==============================================================================
#============================================================================== 
# ** Zlib     
#==============================================================================
module Zlib
  #============================================================================ 
  # ** Png_File     
  #-------------------------------------------------------------------------
  #   Info      : Saves Bitmap to File
  #   Author    : ??? - http://www.66rpg.com/htm/news624.htm
  #============================================================================
  class Png_File < GzipWriter
    #--------------------------------------------------------------------------
    # * Make PNG
    #--------------------------------------------------------------------------
    def make_png(bitmap, mode = 0)
      # Save Bitmap & Mode
      @bitmap, @mode = bitmap, mode
      # Create & Save PNG
      self.write(make_header)
      self.write(make_ihdr)
      self.write(make_idat)
      self.write(make_iend)
    end
    #--------------------------------------------------------------------------
    # * Make Header
    #--------------------------------------------------------------------------
    def make_header
      return [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a].pack('C*')
    end
    #--------------------------------------------------------------------------
    # * Make IHDR
    #--------------------------------------------------------------------------
    def make_ihdr
      ih_size               = [13].pack("N")
      ih_sign               = 'IHDR'
      ih_width              = [@bitmap.width].pack('N')
      ih_height             = [@bitmap.height].pack('N')
      ih_bit_depth          = [8].pack('C')
      ih_color_type         = [6].pack('C')
      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
    #--------------------------------------------------------------------------
    # * Make IDAT
    #--------------------------------------------------------------------------
    def make_idat
      header  = "\x49\x44\x41\x54"
      data    = @mode == 0 ? make_bitmap_data0 : make_bitmap_data1
      data    = Zlib::Deflate.deflate(data, 8)
      crc     = [Zlib.crc32(header + data)].pack('N')
      size    = [data.length].pack('N')
      return size + header + data + crc
    end
    #--------------------------------------------------------------------------
    # * Make Bitmap Data 0
    #--------------------------------------------------------------------------
    def make_bitmap_data0
      gz = Zlib::GzipWriter.open('hoge.gz')
      t_Fx = 0
      w = @bitmap.width
      h = @bitmap.height
      data = []
      for y in 0...h
        data.push(0)
        for x in 0...w
          t_Fx += 1
          if t_Fx % 10000 == 0
            Graphics.update
          end
          if t_Fx % 100000 == 0
            s = data.pack("C*")
            gz.write(s)
            data.clear
          end
          color = @bitmap.get_pixel(x, y)
          red = color.red
          green = color.green
          blue = color.blue
          alpha = color.alpha
          data.push(red)
          data.push(green)
          data.push(blue)
          data.push(alpha)
        end
      end
      s = data.pack("C*")
      gz.write(s)
      gz.close   
      data.clear
      gz = Zlib::GzipReader.open('hoge.gz')
      data = gz.read
      gz.close
      File.delete('hoge.gz')
      return data
    end
    #--------------------------------------------------------------------------
    # * Make Bitmap Data Mode 1
    #--------------------------------------------------------------------------
    def make_bitmap_data1
      w = @bitmap.width
      h = @bitmap.height
      data = []
      for y in 0...h
        data.push(0)
        for x in 0...w
          color = @bitmap.get_pixel(x, y)
          red = color.red
          green = color.green
          blue = color.blue
          alpha = color.alpha
          data.push(red)
          data.push(green)
          data.push(blue)
          data.push(alpha)
        end
      end
      return data.pack("C*")
    end
    #--------------------------------------------------------------------------
    # * Make IEND
    #--------------------------------------------------------------------------
    def make_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
endAnd here's the demo :
http://rataime.free.fr/rmxp/Demos/rataime_demo.zip
Enjoy !

 
 
 Rataime's Image Save Files
 Rataime's Image Save Files