[Script] Spritesheet Generator Conversion Script

Share resources for RPG Maker XP. Uploads must be your own work or have permission to share. Do not share game rips.
Post Reply
User avatar
DerVVulfman
Posts: 31
Joined: Sat Dec 08, 2018 4:25 am
Location: PG, Maryland
Contact:

[Script] Spritesheet Generator Conversion Script

Post by DerVVulfman » Sun Dec 16, 2018 4:15 am

Spritesheet Generator Conversion Script
Version: 1.0



Introduction
For those using an Animated Battler script that needs a battler with a single row of mutiple poses like the Minkoff style. This script lets you convert battler graphics from RPGMaker MV and RPGMaker 2003 formats for use.



Features
  • Hopefully simple to use
  • Keeps the alpha channel(transparency) intact
  • Still a WIP (that's Work in Progress, guys)


Demo
None (yet).



Script

Code: Select all

#==============================================================================
# ** Spritesheet Generator Conversion Script
#    by DerVVulfman
#    11-20-2018 (mm-dd-yyyy)
#------------------------------------------------------------------------------
#
#  How to use?
#  Probably the FASTEST instructions I will give.....
#
#  First, let's set up the project:
#  1) Copy this script into your Scripts Library
#  2) Make an event on your map.  Hey!  Put a character there to talk to!!!
#  3) In the event, make a script call:  $scene = Scene_SpritesheetConv.new
#
#  Now, let's do something:
#  1) Get some non-Minkoffish battler.  Like, make it an RMMV battler
#  2) Paste it in this project's root directory.  Remmember it's name.
#  3) Go into this script's config and put the file's name in the SOURCE value
#  4) Set the SETSTYLE value to 1  .... that means it will convert an RMMV file
#  5) Run the project and talk to your event to make this script run
# 
#  That should do it.  I'll see about making an interface system later.  Maybe
#  even something to adjust which pose goes where.
#
#------------------------------------------------------------------------------
#  
#  A bit of Q&A before I get any...
#  --------------------------------
#  Q:  HEY!  My output isn't all lined up!  
#  A:  Did you set it for the right style of battler? (RMMV or RM2K3)
#  Q:  Yes.  It's an RMMV Battler I found and I set SETSTYLE to 1
#  A:  If some sections are being trimmed or cut off abruptly, the artist
#      may not have paid attention to lining up his individual sprite cels.
#  Q:  Hey, are there any pre-rendered configs for these? 
#  A:  Oh, you mean ...  When I release the new version of the script. ^_^
#
#==============================================================================



#==============================================================================
# ** Spritesheet Generator Conversion Module
#------------------------------------------------------------------------------
#  This is the configuration system for the script.  Beta format for now, it
#  is where you set the filename for both the source and target images.
#  You also select the format for the conversion.
#==============================================================================

module SS_Gen
  
  # -------------------------------------------------------------------------
  # Predefined Style Set Options --------------------------------------------
  STYLE           = {}
  # Style by ID       Style Name          R.  P.  F.  P.  F.
  # ===========       =============       ==  ==  ==  ==  ==
  STYLE[1]        = [ 'RMMV to Single',   3,  18, 3,  18, 3]
  STYLE[2]        = [ 'RM2K3 to Single',  2,  16, 3,  11, 3]
  # -------------------------------------------------------------------------
  
  # SET STYLE
  # =========
  # Choose a style setting.  Currently, there are only 2 settings (1 or 2)
  # which match the two predefine styles above.  
  # 1 = RMMV Conversion / 2 = RM2K3 Conversion
  #
    SETSTYLE = 2
  
  # SOURCE 
  # ======
  # This is the filename for the source image to convert.
  # It is a file in the project's root directory (where you find Game.Exe)
  # Do not supply any .png to the end of the filename.
  #
    SOURCE = 'Source'
  
  # OUTPUT
  # ======
  # This is the filename for the target image to generate.
  # The file will appear in the project's root directory
  # Do not supply any .png to the end of the filename.
  #
  OUTPUT = 'Output2'



end



#==============================================================================
# ** Zlib::Png_File
#------------------------------------------------------------------------------
#  This is a module adds PNG_File class to save Bitmap's to PNG Files
#  =MACL=
#==============================================================================

module Zlib
  class Png_File < GzipWriter
    #------------------------------------------------------------------------
    # * Make PNG
    #     bitmap_Fx : Bitmap Effects
    #     mode      : Mode
    #------------------------------------------------------------------------
    def make_png(bitmap, mode)
      @mode    = mode
      @bitmap  = bitmap
      self.write(make_header)
      self.write(make_ihdr)
      self.write(make_idat)
      self.write(make_iend)
    end
    #------------------------------------------------------------------------
    # * Make PNG Header
    #------------------------------------------------------------------------
    def make_header
      return [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a].pack("C*")
    end
    #------------------------------------------------------------------------
    # * Make Image Information Header
    #------------------------------------------------------------------------
    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 Image Data
    #------------------------------------------------------------------------
    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
    #------------------------------------------------------------------------
    # * Create bitmap data (Mode 0)
    #------------------------------------------------------------------------
    def make_bitmap_data0
      # Create a temporary GZ file
      gz    = Zlib::GzipWriter.open('hoge.gz')
      # Clear frame counter
      t_Fx  = 0
      # Obtain bitmap dimensions and clear temp data
      w     = @bitmap.width
      h     = @bitmap.height
      data  = []
      # Cycle through image vertically
      for y in 0...h
        data.push(0)
        # Cycle horizontally
        for x in 0...w
          # Add to timer FX count
          t_Fx += 1
          # Update Graphics every interval
          Graphics.update if t_Fx % 10000 == 0
          # Write data at intervals
          if t_Fx % 100000 == 0
            s = data.pack("C*")
            gz.write(s)
            data.clear
          end
          # Obtain pixel attributes
          color   = @bitmap.get_pixel(x, y)
          red     = color.red
          green   = color.green
          blue    = color.blue
          alpha   = color.alpha
          # Store attributes in data
          data.push(red)
          data.push(green)
          data.push(blue)
          data.push(alpha)
        end
      end
      # Write, Close and clear data
      s = data.pack("C*")
      gz.write(s)
      gz.close    
      data.clear
      # Obtain formatted data from Temp File
      gz    = Zlib::GzipReader.open('hoge.gz')
      data  = gz.read
      gz.close
      # Delete file and return data
      File.delete('hoge.gz')
      return data
    end
    #--------------------------------------------------------------------------
    # * Create bitmap data (Mode 1)
    #--------------------------------------------------------------------------
    def make_bitmap_data1
      # Obtain bitmap dimensions and clear temp data
      w     = @bitmap.width
      h     = @bitmap.height
      data  = []
      # Cycle through image vertically
      for y in 0...h
        data.push(0)
        # Cycle horizontally
        for x in 0...w
          color = @bitmap.get_pixel(x, y)
          # Obtain pixel attributes
          red   = color.red
          green = color.green
          blue  = color.blue
          alpha = color.alpha
          # Store attributes in data
          data.push(red)
          data.push(green)
          data.push(blue)
          data.push(alpha)
        end
      end
      # Return data
      return data.pack("C*")
    end
    #------------------------------------------------------------------------
    # * Make Image End/EOF Data
    #------------------------------------------------------------------------
    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
end 



#==============================================================================
# ** Bitmap
#------------------------------------------------------------------------------
#  The bitmap class. Bitmaps are expressions of so-called graphics.  Sprites
#  (Sprite) and other objects must be used to display bitmaps on the screen.
#==============================================================================

class Bitmap
  #--------------------------------------------------------------------------
  # * Make PNG (from the MACL)
  #     name : Name of filename
  #     path : Directory in Game Folder
  #     mode : Mode of Writing
  #--------------------------------------------------------------------------
  def make_png(name="like", path="", mode=0)
    # Create the folder path if supplied
    make_dir(path) if path != ""
    Zlib::Png_File.open("temp.gz") {|gz| gz.make_png(self, mode) }
    Zlib::GzipReader.open("temp.gz") {|gz| $read = gz.read }
    f = File.open(path + name + ".png","wb")
    f.write($read)
    f.close
    File.delete('temp.gz')
  end
  #--------------------------------------------------------------------------
  # * Make Directory Path  (Extended from the MACL)
  #     path : Directory in Game Folder
  #--------------------------------------------------------------------------
  def make_dir(path)
    dir = path.split("/")
    dir.each_index {|i|
      next if dir == "."
      add_dir = dir[0..i].join("/")
      begin
        Dir.mkdir(add_dir)
      rescue
      end
    }
  end
end



#==============================================================================
# ** Scene_Title
#------------------------------------------------------------------------------
#  This class performs spritesheet conversion processing.
#==============================================================================

class Scene_SpritesheetConv
  #--------------------------------------------------------------------------
  # * Main Processing
  #--------------------------------------------------------------------------
  def main
    dispose_tempfolder          # Erase temp folder if still exists
    generate_cels               # Generate individual animation cels
    generate_spritesheet        # Generate spritesheet from celse
    dispose_tempfolder          # Erase temp folder
    $scene = Scene_Map.new      # Return to map
    exit
  end
  #--------------------------------------------------------------------------
  # * Get number of rows in source image
  #--------------------------------------------------------------------------
  def source_rows
    SS_Gen::STYLE[SS_Gen::SETSTYLE][1]
  end
  #--------------------------------------------------------------------------
  # * Get number of poses in source image
  #--------------------------------------------------------------------------
  def source_poses
    SS_Gen::STYLE[SS_Gen::SETSTYLE][2]
  end
  #--------------------------------------------------------------------------
  # * Get number of frames for each pose in source image
  #--------------------------------------------------------------------------
  def source_frames
    SS_Gen::STYLE[SS_Gen::SETSTYLE][3]
  end
  #--------------------------------------------------------------------------
  # * Get number of poses to create in target image
  #--------------------------------------------------------------------------
  def target_poses
    SS_Gen::STYLE[SS_Gen::SETSTYLE][4]
  end
  #--------------------------------------------------------------------------
  # * Get number of frames per pose in target image
  #--------------------------------------------------------------------------
  def target_frames  
    # If not entered, same as source
    if SS_Gen::STYLE[SS_Gen::SETSTYLE][5].nil?
      return SS_Gen::STYLE[SS_Gen::SETSTYLE][3]
    end
    SS_Gen::STYLE[SS_Gen::SETSTYLE][5]
  end
  #--------------------------------------------------------------------------
  # * Get total number of frames within each row
  #--------------------------------------------------------------------------
  def frames_per_row
    return source_rows * source_frames
  end
  #--------------------------------------------------------------------------
  # * Get total number of poses within each row
  #--------------------------------------------------------------------------
  def poses_per_row
    source_poses / source_rows
  end
  #--------------------------------------------------------------------------
  # * Generate Cels
  #--------------------------------------------------------------------------
  def generate_cels
    # Initialize the method
    bitmap      = Bitmap.new(SS_Gen::SOURCE)
    count       = 0
    cell_width  = bitmap.width / frames_per_row
    cell_height = bitmap.height / poses_per_row
    # Sort through the original image
    ( 0...source_rows).each { |z| 
      ( 0...poses_per_row).each { |y|
        ( 0...source_frames).each { |x| 
          # Calculate X-Origin in original Multi-Row Spritesheet
          x2 = (x * cell_width) + ((z * source_frames) * cell_width)
          # Cel Count
          count += 1
          # Create temporary image for cel
          temp_cel    = Bitmap.new(cell_width, cell_height)
          # Create Source Rect Area based on cell position in spriesheet
          rect    = Rect.new( x2, y * cell_height, cell_width, cell_height)
          # Generate Name
          name = 'temp_img' + sprintf("%5.5d", count)
          # Paste/Blit cel into bitmap
          temp_cel.blt(0, 0, bitmap, rect)
          # Save Bitmap into Temporary Storage Folder
          temp_cel.make_png(name, 'ImgConvertDir' + '/')
          # Ensure Graphics Module updates (Prevent Lock/Freeze error
          Graphics.update if count % 80 == 0
        }
      }
    }    
  end
  #--------------------------------------------------------------------------
  # * Generate Spritesheet
  #--------------------------------------------------------------------------
  def generate_spritesheet
    # Initialize the method
    files  = Dir.entries('ImgConvertDir') - ['.', '..']
    files.collect! {|filename| Bitmap.new("#{'ImgConvertDir'}/#{filename}") }
    w           = files[0].width
    h           = files[0].height
    # Create temporary image for spritesheet
    temp_image  = Bitmap.new(w * target_frames, h * target_poses)
    # Sort through all files
    files.each_with_index {|img, i|
      x = (i % target_frames) * w
      y = (i / target_frames) * h
      # Paste/Blit cel into spritesheet bitmap
      temp_image.blt(x, y, img, Rect.new(0, 0, w, h))
      # Ensure Graphics Module updates (Prevent Lock/Freeze error
      Graphics.update if (i % 80) == 0
    }
    # Save Generated Bitmap
    temp_image.make_png(SS_Gen::OUTPUT, '')
  end
  #--------------------------------------------------------------------------
  # * Dispose Temp Folder and all contents
  #--------------------------------------------------------------------------
  def dispose_tempfolder
    # Run test for existing directory filenames
    begin
      files  = Dir.entries('ImgConvertDir') - ['.', '..']
    rescue
      return
    end    
    files.each{ |img| File.delete("#{'ImgConvertDir'}/#{img}") }  
    Dir.delete('ImgConvertDir')    
  end
end


Instructions
They're within the script. But I expect that you only alter the SOURCE, the OUTPUT and the SETSTYLE values in the configuration section. Nothing else should be touched. The source graphics must be placed in the root directory of your project, and the output will show up there when done.



FAQ
This utilizes a number of features from the MACL, specifically the ZLib PNG system.



Compatibility
I wrote this with RPGMaker XP in mind. However, it may just work with VX and VXAce with a bit of minor tweaking.



Terms and Conditions
Free for use. It's not expected to be in any actual game. It's a tool afterall
Up is down. Left is right. And sideways is straight ahead.
Image

Post Reply