From: Michael Neumann Date: 2004-11-16T08:15:07+09:00 Subject: Re: bitmaps --------------060203080807000504090503 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Joe Van Dyk wrote: > How can I create a bitmap in Ruby? I have a bunch of RGBA values, and need > to convert them into a bitmap or some other picture format. You can use my appended PNG writer class. Generating PNM images (there very different to PNG!!!) is even simpler. Regards, Michael --------------060203080807000504090503 Content-Type: text/plain; name="png.rb" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="png.rb" # # PNG writer class for true-color images # # Author:: Michael Neumann # Copyright:: (c) 2004 by Michael Neumann # class Array2 attr_reader :values attr_reader :rows, :cols def initialize(rows, cols, &init_block) @rows, @cols = rows, cols @values = (0...rows).collect do |i| (0...cols).collect do |j| if init_block.nil? 0 else init_block.call(i, j) end end end end def each_row(&block) @values.each(&block) end def [](row,col) raise IndexError if row < 0 or col < 0 or row >= @rows or col >= @cols @values[row][col] end def []=(row,col, value) raise IndexError if row < 0 or col < 0 or row >= @rows or col >= @cols @values[row][col] = value end end class RGB attr_accessor :r, :g, :b def initialize(r,g,b) @r, @g, @b = r, g, b end end class PNG_Writer Signature = [137, 80, 78, 71, 13, 10, 26, 10].pack("C*") # pixel_data is an Array2 def write_png(pixel_data, transparent_col=nil, stream="") stream << Signature stream << dump_truecolor_ihdr(pixel_data.cols, pixel_data.rows) if transparent_col != nil t = transparent_col stream << dump_truecolor_tRNS(t.r, t.g, t.b) end stream << dump_truecolor_nofilter_idat(pixel_data) stream << dump_iend return stream end private def dump_chunk(type, data) sz = data.size raise if sz > 2**31-1 crc = CRC.instance.crc(type + data) [sz, type, data, crc].pack("Na*a*N") end COL_TYPE_PALETTE_USED = 1 COL_TYPE_COLOR_USED = 2 COL_TYPE_ALPHA_CHANNEL_USED = 4 def dump_ihdr(width, height, bit_depth, color_type, compression_method, filter_method, interlace_method) data = [width, height, bit_depth, color_type, compression_method, filter_method, interlace_method].pack("NNCCCCC") dump_chunk('IHDR', data) end def dump_truecolor_ihdr(w, h) dump_ihdr(w, h, 8, COL_TYPE_COLOR_USED, 0, 0, 0) end # transparency def dump_truecolor_tRNS(r, g, b) data = [r, g, b].pack("nnn") dump_chunk('tRNS', data) end def dump_iend dump_chunk('IEND', "") end require 'zlib' def dump_truecolor_nofilter_idat(data) # no filter = 0 # produce raw image data string (with filter method byte before each scanline) str = "" data.each_row do |row| str << [0].pack("C") # no filter row.each {|c| str << [c.r, c.g, c.b].pack("CCC") } end data = Zlib::Deflate.deflate(str) dump_chunk('IDAT', data) end class CRC require 'singleton' include Singleton def initialize @crc_table = Array.new(256) make_crc_table end def self.crc(data) instance.crc(data) end def crc(data) update_crc(0xffffffff, data) ^ 0xffffffff end private def update_crc(crc, data) c = crc data.each_byte { |b| c = @crc_table[(c ^ b) & 0xff] ^ (c >> 8) } return c end def make_crc_table (0..255).each { |n| c = n 8.times { c = if c & 1 == 1 then 0xedb88320 ^ (c >> 1) else c >> 1 end } @crc_table[n] = c } end end end if __FILE__ == $0 data = Array2.new(100,100) {|y,x| RGB.new((x+y) % 255 ,0,0) } print PNG_Writer.new.write_png(data) end --------------060203080807000504090503--