--------------060203080807000504090503
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
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:
eflate.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--