Bitmapを書き出してみよう

30分プログラム、その711。Bitmapを読んでみよう - みずぴー日記に書き出し機能をつけてみました。
これで、画像処理で遊べるぜ。
readがBinary -> Bitmapなので、writeはBitmap -> Binaryにしたほうが美しいけれども、オフセットの調節などが難しかったので、直接ファイルに書き出すようにしました。

使い方

test() ->
    % 読み込み
    {ok,Bin} = file:read_file("sample.bmp"),
    Bitmap = read(Bin),
    % 書き出し
    write_file("sample2.bmp",Bitmap).

ソースコード

-module(bitmap).
-compile([export_all]).

-record(file_header,{
	  size,
	  offset
	 }).

-record(info_header,{
	  width,
	  height,
	  planes,
	  bit_count,
	  compression,
	  size,
	  x,
	  y,
	  used,
	  import
	 }).

-define(DWORD,32/unsigned-little-integer).
-define(WORD,16/unsigned-little-integer).

-define(LONG,32/signed-little-integer).

read_file_header(
  <<$B,$M,
   Size: ?DWORD,
   _Reserved1: ?WORD,
   _Reserved2: ?WORD,
   Offset: ?DWORD >>) ->
    #file_header{size=Size,offset=Offset}.

write_file_header(
  #file_header{size=Size,offset=Offset}) ->
    <<$B,$M,
     Size: ?DWORD,
     0: ?WORD,
     0: ?WORD,
     Offset: ?DWORD >>.

read_info_header(
  <<40: ?DWORD,
   Width: ?LONG,
   Height: ?LONG,
   Planes: ?WORD, % Planes
   BitCount:?WORD, % BitCount
   Compression :?DWORD, % Compression
   Size : ?DWORD,
   X : ?DWORD,
   Y : ?DWORD,
   Used : ?DWORD,
   Import:?DWORD
   >>) ->
    #info_header{
		  width=Width,
		  height=Height,
		  planes=Planes,
		  bit_count=BitCount,
		  compression=Compression,
		  size=Size,
		  x=X,
		  y=Y,
		  used=Used,
		  import=Import
		 }.

write_info_header(#info_header{
                  width=Width,
                  height=Height,
		  planes=Planes,
		  bit_count=BitCount,
		  compression=Compression,
		  size=Size,
		  x=X,
		  y=Y,
		  used=Used,
		  import=Import
		 }) ->
    <<40: ?DWORD,
     Width: ?LONG,
     Height: ?LONG,
     Planes: ?WORD, % Planes
     BitCount:?WORD, % BitCount
     Compression :?DWORD, % Compression
     Size : ?DWORD,
     X : ?DWORD,
     Y : ?DWORD,
     Used : ?DWORD,
     Import:?DWORD>>.

get_bin(Bin, N)->
    {X,_} = split_binary(Bin,N),
    X.

read(Bin) ->
    {Bin1, Bin2} = split_binary(Bin,14),
    FileHeader = read_file_header(Bin1),
    InfoHeader = read_info_header(get_bin(Bin2,40)),
    #file_header{offset=Offset} = FileHeader,
    {_,Data} = split_binary(Bin,Offset),
    {FileHeader,InfoHeader,Data}.

write_file(Path,{FileHeader,InfoHeader,Data}) ->
    #file_header{offset=Offset} = FileHeader,
    {ok,Io} = file:open(Path,[write,binary,raw]),
    file:pwrite(Io,[{0 ,write_file_header(FileHeader)},
		    {14,write_info_header(InfoHeader)},
		    {Offset,Data}]),
    file:close(Io).

example() ->
    {ok,Bin} = file:read_file("sample.bmp"),
    Bitmap = read(Bin),
    write_file("sample2.bmp",Bitmap).