Project1

标题: 将Bitmap对象输出成PNG文件 优化版 [打印本页]

作者: 轮回者    时间: 2006-11-19 00:14
标题: 将Bitmap对象输出成PNG文件 优化版
http://ftp2.66rpg.com/3/美术与技术/轮回者/TilesetMaker_Fx4.rar

128m的机器2000*1000的图输出大约30s,
应该不会再出现“脚本已备份”了。
多谢66、金圭子和夏娜的提醒{/cy}
现在主要是get_pixel的效率问题……管不了,不管了。

  1. #==============================================================================
  2. #               本脚本出自www.66rpg.com,转载请注明。
  3. #==============================================================================
  4. =begin
  5. ==============================================================================
  6.                         Bitmap to PNG By 轮回者
  7. ==============================================================================

  8. 对Bitmap对象直接使用

  9. bitmap_obj.make_png(name[, path])

  10. name:保存文件名
  11. path:保存路径

  12. 感谢66、夏娜、金圭子的提醒和帮助!
  13.    
  14. ==============================================================================
  15. =end

  16. module Zlib
  17.   class Png_File < GzipWriter
  18.     #--------------------------------------------------------------------------
  19.     # ● 主处理
  20.     #--------------------------------------------------------------------------
  21.     def make_png(bitmap_Fx,mode)
  22.       @mode = mode
  23.       @bitmap_Fx = bitmap_Fx
  24.       self.write(make_header)
  25.       self.write(make_ihdr)
  26.       self.write(make_idat)
  27.       self.write(make_iend)
  28.     end
  29.     #--------------------------------------------------------------------------
  30.     # ● PNG文件头数据块
  31.     #--------------------------------------------------------------------------
  32.     def make_header
  33.       return [0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a].pack("C*")
  34.     end
  35.     #--------------------------------------------------------------------------
  36.     # ● PNG文件情报头数据块(IHDR)
  37.     #--------------------------------------------------------------------------
  38.     def make_ihdr
  39.       ih_size = [13].pack("N")
  40.       ih_sign = "IHDR"
  41.       ih_width = [@bitmap_Fx.width].pack("N")
  42.       ih_height = [@bitmap_Fx.height].pack("N")
  43.       ih_bit_depth = [8].pack("C")
  44.       ih_color_type = [6].pack("C")
  45.       ih_compression_method = [0].pack("C")
  46.       ih_filter_method = [0].pack("C")
  47.       ih_interlace_method = [0].pack("C")
  48.       string = ih_sign + ih_width + ih_height + ih_bit_depth + ih_color_type +
  49.                ih_compression_method + ih_filter_method + ih_interlace_method
  50.       ih_crc = [Zlib.crc32(string)].pack("N")
  51.       return ih_size + string + ih_crc
  52.     end
  53.     #--------------------------------------------------------------------------
  54.     # ● 生成图像数据(IDAT)
  55.     #--------------------------------------------------------------------------
  56.     def make_idat
  57.       header = "\x49\x44\x41\x54"
  58.       case @mode # 请54~
  59.       when 1
  60.         data = make_bitmap_data#1
  61.       else
  62.         data = make_bitmap_data
  63.       end
  64.       data = Zlib::Deflate.deflate(data, 8)
  65.       crc = [Zlib.crc32(header + data)].pack("N")
  66.       size = [data.length].pack("N")
  67.       return size + header + data + crc
  68.     end
  69.     #--------------------------------------------------------------------------
  70.     # ● 从Bitmap对象中生成图像数据 mode 1(请54~)
  71.     #--------------------------------------------------------------------------
  72.     def make_bitmap_data1
  73.       w = @bitmap_Fx.width
  74.       h = @bitmap_Fx.height
  75.       data = []
  76.       for y in 0...h
  77.         data.push(0)
  78.         for x in 0...w
  79.           color = @bitmap_Fx.get_pixel(x, y)
  80.           red = color.red
  81.           green = color.green
  82.           blue = color.blue
  83.           alpha = color.alpha
  84.           data.push(red)
  85.           data.push(green)
  86.           data.push(blue)
  87.           data.push(alpha)
  88.         end
  89.       end
  90.       return data.pack("C*")
  91.     end
  92.     #--------------------------------------------------------------------------
  93.     # ● 从Bitmap对象中生成图像数据 mode 0
  94.     #--------------------------------------------------------------------------
  95.     def make_bitmap_data
  96.       gz = Zlib::GzipWriter.open('hoge.gz')
  97.       t_Fx = 0
  98.       w = @bitmap_Fx.width
  99.       h = @bitmap_Fx.height
  100.       data = []
  101.       for y in 0...h
  102.         data.push(0)
  103.         for x in 0...w
  104.           t_Fx += 1
  105.           if t_Fx % 10000 == 0
  106.             Graphics.update
  107.           end
  108.           if t_Fx % 100000 == 0
  109.             s = data.pack("C*")
  110.             gz.write(s)
  111.             data.clear
  112.             #GC.start
  113.           end
  114.           color = @bitmap_Fx.get_pixel(x, y)
  115.           red = color.red
  116.           green = color.green
  117.           blue = color.blue
  118.           alpha = color.alpha
  119.           data.push(red)
  120.           data.push(green)
  121.           data.push(blue)
  122.           data.push(alpha)
  123.         end
  124.       end
  125.       s = data.pack("C*")
  126.       gz.write(s)
  127.       gz.close   
  128.       data.clear
  129.       gz = Zlib::GzipReader.open('hoge.gz')
  130.       data = gz.read
  131.       gz.close
  132.       File.delete('hoge.gz')
  133.       return data
  134.     end
  135.     #--------------------------------------------------------------------------
  136.     # ● PNG文件尾数据块(IEND)
  137.     #--------------------------------------------------------------------------
  138.     def make_iend
  139.       ie_size = [0].pack("N")
  140.       ie_sign = "IEND"
  141.       ie_crc = [Zlib.crc32(ie_sign)].pack("N")
  142.       return ie_size + ie_sign + ie_crc
  143.     end
  144.   end
  145. end
  146. #==============================================================================
  147. # ■ Bitmap
  148. #------------------------------------------------------------------------------
  149. #  关联到Bitmap。
  150. #==============================================================================
  151. class Bitmap
  152.   #--------------------------------------------------------------------------
  153.   # ● 关联
  154.   #--------------------------------------------------------------------------
  155.   def make_png(name="like", path="",mode=0)
  156.     make_dir(path) if path != ""
  157.     Zlib::Png_File.open("temp.gz") {|gz|
  158.       gz.make_png(self,mode)
  159.     }
  160.     Zlib::GzipReader.open("temp.gz") {|gz|
  161.       $read = gz.read
  162.     }
  163.     f = File.open(path + name + ".png","wb")
  164.     f.write($read)
  165.     f.close
  166.     File.delete('temp.gz')
  167.     end
  168.   #--------------------------------------------------------------------------
  169.   # ● 生成保存路径
  170.   #--------------------------------------------------------------------------
  171.   def make_dir(path)
  172.     dir = path.split("/")
  173.     for i in 0...dir.size
  174.       unless dir == "."
  175.         add_dir = dir[0..i].join("/")
  176.         begin
  177.           Dir.mkdir(add_dir)
  178.         rescue
  179.         end
  180.       end
  181.     end
  182.   end
  183. end
  184. #==============================================================================
  185. #               本脚本出自www.66rpg.com,转载请注明。
  186. #==============================================================================
复制代码



              [本贴由 雷欧纳德 于 2006-11-28 17:05:45 进行了编辑]
作者: 轮回者    时间: 2006-11-19 00:14
标题: 将Bitmap对象输出成PNG文件 优化版
本帖最后由 后知后觉 于 2009-12-13 16:24 编辑

重复内容……
作者: 美兽    时间: 2006-11-19 00:38
这个ORZ......
一直不知道.pack这个是什么意思,哪里有相关资料吗?
作者: 轮回者    时间: 2006-11-19 00:40
下了个ruby1.82
里面有

就是把数字/字符以特定字节输出,并有什么低字节在前,在后的区别。

比如[10].pack("L") => 00 00 00 0a (好像是这样)
作者: 美兽    时间: 2006-11-19 00:42
哪里有ruby1.82......{/pz}
作者: 轮回者    时间: 2006-11-19 00:43
日本网站,我在学校下的。
baidu可以搜到地址
作者: 美兽    时间: 2006-11-19 01:38
我大概是很认真的搜索了,翻了十页,但还是没搜索到相关资料。

只是想知道pack("N")pack("C*")pack("C*")pack("S")pack("a2")pack("L")括号里面那些都是什么意思{/pz}
作者: 轮回者    时间: 2006-11-19 01:42
pack("C") 1字节(数字)
pack("S")pack("L")4字节(数字)
pack("N")2字节(数字)?
pack("an")n字节(字符)
不加*只对数组中第一个单元进行输出,加则对所有
昨天把A-Z都试了一遍,X不可用,其他大都是用于数字的。

在ruby_c_string

ms是这个

搜索pack就可以
作者: 轮回者    时间: 2006-11-19 01:43
具体的表不记得在什么位置了
作者: 美兽    时间: 2006-11-19 01:45
谢谢,不查了,只要知道那几个的意思就行了。
作者: 雷欧纳德    时间: 2006-11-19 04:47
http://rubycn.ce-lab.net/man/pack_template_string.html
作者: 亿万星辰    时间: 2006-11-19 15:30
之前研究过很长时间PNG的构造,不过那些CRC函数太变态,最终放弃
作者: 柳柳    时间: 2006-11-19 15:34
呦~亿万!网络好了吗?
作者: 柳柳    时间: 2006-11-19 15:37
看了一下具体内容,只能用“wo kao~~”来形容我的心情。

不过有一点问题,也是我之前一直想改进却不得成功的地方。

就是输出的图啊,如果太大的话,怎么能在脚本备份之前完成呢?虽然替换的凑合的方法也有,不过总是很别扭。比如1000×2000的图我这里就未必能输出出来了,1000×3000基本就over了。

还有这个图输出之后体积好大,1000×1000的纯红色图体积高达3.9M,用photoshop重新保存一下变成了6K...{/gg}
作者: 亿万星辰    时间: 2006-11-19 15:40
那个PNG的文件构造是相当的神奇啊~~~虽然用其他的语言能够生成,但是一想到用RGSS,就有点崩溃的感觉呢~~~~~{/hx}

网络怎么会好,我不是说过每天早上8点前能上,8点01就会喀嚓。
经检查,已确定不是我这里网络的问题了……只能归根于百什么了。
作者: 柳柳    时间: 2006-11-19 15:51
亿万你编个dll输出png吧,拼图器就有希望了。

不不,干脆用vb什么的做个拼图器多好
作者: BB崽    时间: 2006-11-19 18:46
这么邪恶的帖子怎么可以少我了{/hx}
作者: 轮回者    时间: 2006-11-20 20:50
更新了
作者: 轮回者    时间: 2006-11-20 20:52
改成绿色的标题没问题吧?

至于CRC,我用Zilb::Gzip输出的
作者: 轮回者    时间: 2006-11-20 21:13
至于 “脚本备份”,似乎是我没用某个Graphic.update(没拼错吧?)……
需要的话在适当位置加上好了
作者: 轮回者    时间: 2006-11-20 21:18
比如:

    for y in 0...h
Graphic.update
      1.times do
        data.push(0)
      end

(不要怪我分开打,我们学校的机器烂的可以……-_-b)
作者: 柳柳    时间: 2006-11-20 21:52
以下引用轮回者于2006-11-20 13:18:08的发言:

比如:

   for y in 0...h
Graphic.update
     1.times do
       data.push(0)
     end

(不要怪我分开打,我们学校的机器烂的可以……-_-b)

绝对不行,2000×1000的图得刷到猴年马月

我本来是设计

if Time.now.to_i - @tm >= 5
  Graphics.update
  @tm = Time.now.to_i
end

但是实际上图一大了,内存碎片就多,最后根本输不出来。能不能先在开始前声明3~5M的内存空间?
作者: 轮回者    时间: 2006-11-21 01:04
这个……似乎超出我能力范围了。

转bmp的有这种问题么?

或者
if Time.now.to_i - @tm >= 5
p "处理中"
@tm = Time.now.to_i
end
作者: 轮回者    时间: 2006-11-21 16:22
看看这次的
作者: 金圭子    时间: 2006-11-21 18:42
没发现在楼顶更新了,不好意思。
作者: 金圭子    时间: 2006-11-21 19:20
对了,看到你在里面提到:

     2、由于Ruby::IO输出"\x0a"时实际输出的是"\x0d\x0a",导致生成Png文件
        时会出现错误,所以实际是用Zlib输出的.gz的压缩文件,需自己解压。
(png_file 第24行)

这个是有办法的,上次在你哪个帖子里面看到,忘了和你说一下(那个帖子找不到了)
是在write之前,加一句:
file.binmode

比如你试试看这个:
file = File.open("IOtest.txt","w")  
file.binmode
file.write("\x0a")
file.write("\n")
file.write("\cJ")
# 三句话的意思一样,都是写\x0a
file.close

注意,这个binmode之后,是不能从二进制模式回到文本模式的(如果要用,只能退出重开,F1里面就是这么写的),我没仔细的看你这个bmp转png的全程序,到底是哪里要写\x0a,如果你从头到尾都是在写二进制的图片文件,而不是在写文章,那我建议你还是直接用binmode,还可以避免些其他情况(比如空格和0的情况等等)
作者: 雷欧纳德    时间: 2006-11-21 20:45
以下引用金圭子于2006-11-21 11:20:20的发言:

对了,看到你在里面提到:

    2、由于Ruby::IO输出"\x0a"时实际输出的是"\x0d\x0a",导致生成Png文件
       时会出现错误,所以实际是用Zlib输出的.gz的压缩文件,需自己解压。
(png_file 第24行)

这个是有办法的,上次在你哪个帖子里面看到,忘了和你说一下(那个帖子找不到了)
是在write之前,加一句:
file.binmode

比如你试试看这个:
file = File.open("IOtest.txt","w")  
file.binmode
file.write("\x0a")
file.write("\n")
file.write("\cJ")
# 三句话的意思一样,都是写\x0a
file.close

注意,这个binmode之后,是不能从二进制模式回到文本模式的(如果要用,只能退出重开,F1里面就是这么写的),我没仔细的看你这个bmp转png的全程序,到底是哪里要写\x0a,如果你从头到尾都是在写二进制的图片文件,而不是在写文章,那我建议你还是直接用binmode,还可以避免些其他情况(比如空格和0的情况等等)


呵呵 直接 file = open("IOtest.txt","wb")即可``
作者: 轮回者    时间: 2006-11-21 20:59
多谢楼上的了
恩,回家试试
一直不知道file.binmode是干什么的……
作者: 金圭子    时间: 2006-11-21 21:29
以下引用灼眼的夏娜于2006-11-21 12:45:31的发言:
呵呵 直接 file = open("IOtest.txt","wb")即可``

嗯,也是。
to轮回者:我也是看到你这个,然后去F1帮助里面搜索了一下write。
然后发现的确只有一个write,就看到write上面几个就有binmode,抱着试试看的想法,直接用,不行,然后去baidu搜索“ruby binmode”,才学到怎么用的。用了用可以,就发给你了。
倒是忘了几乎所有的用open方式,有w的,几乎都有r、w、b等等方式的。
见笑了~~
作者: 雷欧纳德    时间: 2006-11-22 19:53
呵呵,提供一个crc码计算方法`````

方法一:
def make_crc_table
  crc_table = []
  for i in 0...256
    c = i
    for j in 0...8
      if (c & 1) == 1
        c = 0xedb88320^(c>>1)
      else
        c = c>>1
      end
    end
    crc_table = c
  end
  return crc_table
end

def crc_make(string)
  crc_table = self.make_crc_table
  c = 0xffffffff
  for i in 0...string.size
    c = crc_table[(c^string)&0xff]^(c>>8)
  end
  return c^0xffffffff
end

p sprintf("%x",crc_make("IEND"))

方法二:
Zlib.crc_table          # crc_table
Zlib.crc32(string)      # crc 码
Zlib.adler32(string)    # adler 码
作者: 九泪    时间: 2006-11-22 21:52
以下引用柳柳于2006-11-19 7:37:58的发言:

看了一下具体内容,只能用“wo kao~~”来形容我的心情。

不过有一点问题,也是我之前一直想改进却不得成功的地方。

就是输出的图啊,如果太大的话,怎么能在脚本备份之前完成呢?虽然替换的凑合的方法也有,不过总是很别扭。比如1000×2000的图我这里就未必能输出出来了,1000×3000基本就over了。

还有这个图输出之后体积好大,1000×1000的纯红色图体积高达3.9M,用photoshop重新保存一下变成了6K...


wo kao 一下....飘走...
作者: 金圭子    时间: 2006-11-22 22:40
以下引用柳柳于2006-11-19 7:37:58的发言:
还有这个图输出之后体积好大,1000×1000的纯红色图体积高达3.9M,用photoshop重新保存一下变成了6K...
是有压缩和没压缩的区别吧,我记得png可以选择压缩和不压缩两种算法的…………

作者: 金圭子    时间: 2006-11-22 22:44
以下引用柳柳于2006-11-19 7:51:23的发言:

亿万你编个dll输出png吧,拼图器就有希望了。

不不,干脆用vb什么的做个拼图器多好

拼图器是用来干吗的?
就是做那个商业素材拼接效果么?


上次帮某个vip做的时候才发现,gif Movie Gear也有问题,因为人家是为了gif服务的,透明什么的考虑的很差,几乎图出来就是索引的,害的带透明色的图拼不出来,不过柳柳你演示里面的那种黑底没有透明最后准备用加法的,用gif Movie Gear大概就是几秒钟的事情,比你那样拼快多了。那个vip主要一定要用普通不想用加法…………
作者: 轮回者    时间: 2006-11-25 02:54
最后一次更新……
参考夏娜的脚本优化了一下,无他。{/cy}
作者: emil    时间: 2006-11-25 20:13
提示: 作者被禁止或删除 内容自动屏蔽




欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1