class Bitmap
FILE_HEADER = "S<L<S<S<L<"
INFO_HEADER = "L<l<l<S<S<L<L<l<l<L<L<"
BM = 'B'.ord+('M'.ord<<8)
CCC = "CCC".freeze
attr_reader :width
attr_reader :height
attr_reader :blob
def initialize width, height, blob="\0"*(width*height*3)
@width = width
@height = height
@blob = blob
end
def self.load filename
open filename,"rb" do |file|
header = file.read(14).unpack FILE_HEADER
raise unless header[0]==BM
raise unless header[1]==file.size
raise unless header.last==54
dib = file.read(40).unpack INFO_HEADER
raise unless dib[4]==24
width, height = dib[1,2]
raise unless height>0
blob = "\0"*(width*height*3)
(height-1).downto 0 do |y|
0.upto(width-1) do |x|
b, g, r = file.read(3).unpack CCC
blob[(y*width+x)*3,3] = [r,g,b].pack CCC
end
file.read(width%4)
end
self.new width, height, blob
end
end
def save filename
raise unless @blob.size==@width*@height*3
size = (24*@width+31).div(32)*4*@height
header = [BM, size+54, 0, 0, 54]
dib = [40, @width, @height, 1, 24, 0, size, 3780, 3780, 0, 0]
open filename,"wb" do |file|
file.write header.pack FILE_HEADER
file.write dib.pack INFO_HEADER
(@height-1).downto 0 do |y|
0.upto(@width-1) do |x|
r, g, b = @blob[(y*@width+x)*3,3].unpack CCC
file.write [b, g, r].pack CCC
end
file.write "\0"*(@width%4)
end
end
nil
end
def [] x,y
@blob[(y*@width+x)*3,3].unpack CCC
end
def []= x,y,rgb
@blob[(y*@width+x)*3,3] = rgb.pack CCC
end
end
def Bitmap::run_test
b = Bitmap.load "test.bmp"
b2 = Bitmap.new(b.width*2,b.height*2)
for y in 0...b.height
for x in 0...b.width
rgb = b[x,y]
b2[x*2,y*2] = rgb
b2[x*2,y*2+1] = [0,0,255]
b2[x*2+1,y*2] = rgb
b2[x*2+1,y*2+1] = [128,0,0]
end
end
b2.save "test2.bmp"
puts 'ok'
end
Bitmap::run_test if __FILE__ == $0
Only 24-bit bmp file is supported here。