TwlIPL/build/tools/iconMaker/bmp.rb
aoki_ryoma 591c0b6568 初版
git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlIPL/trunk@2305 b08762b0-b915-fc4b-9d8c-17b2551a87ff
2008-08-28 06:49:50 +00:00

197 lines
4.9 KiB
Ruby
Executable File

# ruby用bmp操作ライブラリ
# パレットはwindows標準の固定16色に決め打ち
# 出力するときはTwlIconクラスのfgColorとbgColorで該当パレットを置換する
class BitMap
PALETTE_SIZE = 16*4
def initialize(width, height, dpi = 96)
@width = width
@height = height
@line_size = (width + (8 - width % 8 ) % 8) / 2
@buf_size = @line_size * height
@buf = [ 0x00 ] * @buf_size
@bit_count = 4
@compression = 0 # 圧縮無し
@size_image = 0
@x_pix_per_meter = 0
@y_pix_per_meter = 0
@clr_used = 16
@cir_important = 0
@palette_size = (2**@bit_count) * 4
@palette = "\x00\x00\x00\x00\x00\x00\x80\x00\x00\x80\x00\x00\x00\x80\x80\x00" +
"\x80\x00\x00\x00\x80\x00\x80\x00\x80\x80\x00\x00\x80\x80\x80\x00" +
"\xC0\xC0\xC0\x00\x00\x00\xFF\x00\x00\xFF\x00\x00\x00\xFF\xFF\x00" +
"\xFF\x00\x00\x00\xFF\x00\xFF\x00\xFF\xFF\x00\x00\xFF\xFF\xFF\x00"
#puts "Initialize..."
#p "width :#{@width} line_size :#{@line_size}"
end
def clear( clrIdx = 15 )
@buf = [ (clrIdx << 4) + clrIdx ] * @height * @line_size
end
attr_writer :buf
attr_reader :width, :height
# BMPファイルを出力する
def write(filename)
file_size = 14 + 40 + @palette_size + @buf_size
palette_offset = 14 + 40
data_offset = palette_offset + @palette_size
open(filename, "wb") do |f|
f.print 'BM'
f.print [file_size, 0, data_offset].pack("l*")
f.print [40, @width, @height].pack("l*")
f.print [1, @bit_count].pack("S*")
f.print [@compression, @size_image,
@x_pix_per_meter, @y_pix_per_meter,
@clr_used, @cir_important].pack("l*")
f.print @palette
f.print @buf.pack("c*")
end
end
# BMPファイルを読み込む
def BitMap.read(filename)
buf = nil
open(filename, "rb") do |f|
buf = f.read
end
if buf[0] != ?B or buf[1] != ?M
raise('[Error] read: Invalid Header')
end
real_buf_size = buf.size
buf_size = (buf[2, 4].unpack("l*"))[0]
if buf_size > real_buf_size
raise('[Error] read: Invalid Buffer Size')
end
data_offset = (buf[10, 4].unpack("l*"))[0]
if data_offset != 54 + PALETTE_SIZE
raise('[Error] read: Invalid Data Offset')
end
width = (buf[18, 4].unpack("l*"))[0]
height = (buf[22, 4].unpack("l*"))[0]
bit_count = (buf[28, 2].unpack("s*"))[0]
if bit_count != 4
raise('[Error] read: Unsupported Color Depth')
end
compression = (buf[30, 4].unpack("l*"))[0]
if compression != 0
raise('[Error] read: Compression Not Supported')
end
pix_per_meter = (buf[38, 4].unpack("l*"))[0]
dpi = pix_per_meter / 39.375
image_buf = buf[54 + PALETTE_SIZE, buf_size].unpack("C*")
image = BitMap.new(width, height, dpi)
image.buf = image_buf
return image
end
# (x1, y1) - (x2, y2)の部分画像を取り出す
def clip(x1, y1, x2, y2)
return if x1 > x2
return if y1 > y2
return if x2 < 0
return if y2 < 0
return if x1 >= @width
return if y1 >= @height
x1 = 0 if x1 < 0
y1 = 0 if y1 < 0
x2 = @width - 1 if x2 >= @width
y2 = @height - 1 if y2 >= @height
clip_width = x2 - x1 + 1
clip_height = y2 - y1 + 1
clip_image = BitMap.new(clip_width, clip_height, self.get_dpi)
for y in 0 .. (clip_height - 1)
for x in 0 .. (clip_width - 1)
color = self.pget(x1 + x, y1 + y)
clip_image.pset(x, y, color)
end
end
return clip_image
end
# x, y, r, g, b は整数であることを期待している
def pset(x, y, clr)
return if x < 0 or @width <= x
return if y < 0 or @height <= y
clr = 0 if clr < 0
clr = 15 if clr > 15
nowClr = @buf[(@height - 1 - y) * @line_size + x / 2]
if x%2 == 0 then
nowClr = (nowClr & 0x0F) + (clr << 4)
else
nowClr = (nowClr & 0xF0) + clr
end
@buf[(@height - 1 - y) * @line_size + x / 2] = nowClr
end
# x, yは整数であることを期待している
# 戻り値はパレットのインデクス整数値
def pget(x, y)
x = 0 if x < 0
x = @width - 1 if x >= @width
y = 0 if y < 0
y = @height - 1 if y >= @height
addr = (@height - 1 - y) * @line_size + x / 2
if x%2 == 0 then
retValue = @buf[addr] >> 4
else
retValue = @buf[addr] & 0x0F
end
return retValue
end
def get_dpi()
return (@x_pix_per_meter / 39.375).round
end
def set_dpi(dpi)
@x_pix_per_meter = (39.375 * dpi).round
@y_pix_per_meter = @x_pix_per_meter
end
# x0, y0 は、貼り付ける始点(左上)の座標
def paste(image, x0 = 0, y0 = 0)
return if image == nil
image.height.times do |from_y|
y = y0 + from_y
next if y < 0 or @height <= y
image.width.times do |from_x|
x = x0 + from_x
next if x < 0 or @width <= x
color = image.pget(from_x, from_y)
self.pset(x, y, color)
end
end
end
end