Permanent
Creation

RPGツクールXP/VX用のRGSS素材です。
一部英語版対応です。 (A few materials can be used for English RPG MAKER XP/VX.)
競合率はルファーの独断と偏見なのでたまにハズレます。


#==============================================================================
# ■ DIB 出力ライブラリ
#------------------------------------------------------------------------------
#  ビットマップオブジェクトを DIB (*.bmp) ファイルに出力します。
# 対応RGSS : 1 2
# (C) ルファー
# WebSite https://tkoolerlufar.pages.dev/
#==============================================================================

=begin
  =対応RGSS
  1 2

  =必要なライブラリ
  ルファー作スクリプト素材共通ライブラリ

  =他の素材との競合の可能性
  ... 考える必要ナシ

  =RPGツクールXPでの導入方法
  Main より上に新セクションを作成して、このプログラムをそこにコピーする

  =使い方。
  Bitmap クラスの「write_to_bmp_file」メソッドを呼び出すことで、
  そのビットマップを bmp ファイルに出力します。
  文法:
    write_to_bmp_file(file[, show_progress])
    * file          : 出力先ファイルのパスまたは出力先 IO
    * show_progress : 進歩状況を表示するかどうか (初期値 true)
  show_progress を true にしても、メモリが無いと進行状況を表示しません。
  なお、RPGツクールXPでは、この引数に false を与えると
  ハングアップすることがあるので気をつけてください。

  =出力する DIB について。
  ビットマップオブジェクトの幅か高さのいずれかが
  2,147,483,647 ピクセルを超えると出力できません。
  ま、そんなビットマップ作らないと思うけど。
  解像度は、はがきサイズ (横10cm X 縦14.1cm) に合わせます。
  透明ピクセルの色は不明です。隠しピクセルとかあるかも?
  試しにウィンドウスキンの「001-Blue01」を出力してみてはどうでしょう。

  =参考サイト。ありがとうございます!
  Wikipedia
    http://ja.wikipedia.org/wiki/Windows_bitmap
    http://en.wikipedia.org/wiki/Device-independent_bitmap
  MSDN オンライン
    http://msdn.microsoft.com/en-us/library/dd183374(VS.85).aspx
    http://msdn.microsoft.com/en-us/library/dd183376(VS.85).aspx

  =更新履歴
  2010/06/01 解像度が、はがきの背景サイズに合わせていたのを前景サイズに修正
  2010/04/13 公開

  =新規定義しているメソッド
  Bitmap#write_to_bmpfile
=end
#----------------------------------------------------------------------------
# ◆ Bitmap クラス
#----------------------------------------------------------------------------
class Bitmap
  #--------------------------------------------------------------------------
  # ○ DIB ファイルへの書き込み
  #     file          : 出力先ファイルのパスまたは出力先 IO
  #     show_progress : 進歩状況を表示するかどうか (初期値 true)
  #--------------------------------------------------------------------------
  def write_to_bmpfile(file, show_progress = true)
    if width > 0x7fffffff or height > 0x7fffffff
      raise(RuntimeError, "ビットマップが大きすぎます。", caller)
    end
    begin
      # 「お待ちください」
      if show_progress
        begin
          colorless = Color.new(0.0, 0.0, 0.0, 0.0)
          sprite = Sprite.new
          sprite.z = 077777
          sprite.bitmap = Bitmap.new(screen_width, screen_height)
          sprite.bitmap.fill_rect(0, 0, screen_width, screen_height,
            colorless)
          sprite.bitmap.draw_text(0, screen_height / 2 - 32, screen_width, 32,
            "WRITING A BITMAP TO A DIB IMAGE. PLEASE WAIT....", 1)
          sprite.bitmap.font.color = Color.new(128.0, 128.0, 128.0)
        rescue RGSSError
          raise if $!.message !~ /^failed to create /
          show_progress = false
        end
      end
      refresh_progress = Proc.new {|str|
        next unless show_progress
        sprite.bitmap.fill_rect(0, screen_height / 2, screen_width, 32,
          colorless)
        sprite.bitmap.draw_text(0, screen_height / 2, screen_width, 32, str)
      }
      # 何秒もビジー状態になると不安になってくるので
      # 別スレッドで進歩状況を表示しながら処理
      processing = true
      thread_which_update_frame = Thread.start do
        unless show_progress
          Thread.stop
          Thread.exit
        end
        frame_count = Graphics.frame_count
        frame_rate = Graphics.frame_rate
        Graphics.frame_count = 0
        Graphics.frame_rate = 10
        while processing
          sprite.visible = Graphics.frame_count & 0b10 != 0
          Graphics.update
          sleep(0.5 / Graphics.frame_rate)
        end
        Graphics.frame_count = frame_count
        Graphics.frame_rate = frame_rate
        sprite.bitmap.dispose
        sprite.dispose
      end
      # メイン処理
      ## ファイルサイズ計算
      bmp_size = (self.width * 3 + self.width % 4) * self.height
      file_size = 14
      file_size += 40
      file_size += bmp_size
      ## BITMAPFILEHEADER
      refresh_progress.call("file header")
      packed_fh = Array.new
      packed_fh << "BM"       # 識別子
      packed_fh << file_size  # ファイルサイズ
      packed_fh <<         0  # 予約A
      packed_fh <<         0  # 予約B
      packed_fh <<   14 + 40  # 画像データの開始位置
      ## BITMAPINFOHEADER
      refresh_progress.call("information header")
      resolution =
        [self.width * 10, Integer(self.height * 5.0 * Math.sqrt(2.0))].max
      packed_ih = Array.new
      packed_ih <<          40  # BITMAPINFOHEADER のサイズ
      packed_ih << self.width   # 幅
      packed_ih << self.height  # 高さ
      packed_ih <<           1  # 面の数
      packed_ih <<          24  # ビット深度
      packed_ih <<           0  # 圧縮方式
      packed_ih << bmp_size     # 画像データのサイズ
      packed_ih << resolution   # 横解像度 [ピクセル/m]
      packed_ih << resolution   # 縦解像度
      packed_ih <<   0  # 使っている色数
      packed_ih <<   0  # 重要な色数
      ## 画像データ
      refresh_progress.call("image data")
      image_data = String.new
      self.height.times do |_y|
        y = self.height - 1 - _y
        refresh_progress.call(sprintf(
          "image data (%d%%)", _y * 100 / self.height))
        self.width.times do |x|
          px = self.get_pixel(x, y)
          image_data << px.blue.to_i
          image_data << px.green.to_i
          image_data << px.red.to_i
        end
        (self.width % 4).times {|i| image_data << 0 }
      end
      ## 書く
      refresh_progress.call("")
      out = file.instance_of?(String) ? File.open(file, "wb") : file
      out.print(
        packed_fh.pack("a2VvvV") + packed_ih.pack("VVVvvVVVVVV") + image_data)
      out.close if file.instance_of?(String)
      processing = false
      thread_which_update_frame.run.join
      return false
    rescue SystemCallError
      $@ = caller
      processing = false
      thread_which_update_frame.run.join
      raise
    end
  end
end

戻る