アットウィキロゴ
yi01.memo
掲示板 掲示板 ページ検索 ページ検索 メニュー メニュー

yi01.memo

2008-01-14

最終更新:

yi01memo

- view
管理者のみ編集可

C#でPGM形式の画像ファイルをバイナリで作成するときにつまずきやすい点

アスキーモードならすんなりいくのに・・・

PGMの画像形式はアスキーモードでは
P2\n
#コメント
\n
640 480\n
255\n
(データ 1行最大70字、区切り文字はホワイトスペース)
で、初心者でもすぐに書けると思います。
僕自身、授業でCでやったときはここでつまずくことはありませんでした。C#でやってみても、こっちはすんなりいきました。

バイナリモード?

PGMの画像形式はバイナリモードでは
P5\n
#コメント
\n
640 480\n
255\n
(データ 区切り文字はいらない)
そもそも「バイナリモード」とか「バイナリファイル」って何?ってところから始まったわけですが、
Cならファイルのオープンの時に"r"→"rb"、"w"→"wb"みたいにbをつけるだけで、
C#ならStreamWriterのかわりにBinaryWriterを使うだけで、
ほとんど同じ操作でこの「バイナリファイル」なるものを作れるようです。
バイナリファイルはテキストエディタじゃ読めないので、バイナリエディタとかいうカテゴリに入るようなソフトをダウンロードしてくる必要があります。僕はStirlingとかいうのを使いました。

バイナリモードの罠

C#のBinaryWriterのWriteメソッドにはいくつか厄介な点があります。そこではめられ、3時間を無駄にしてしまいました。

int→stringを勝手にするんじゃない

640 480\n
255\n
この部分は、普通に
BinaryWriter bw=new BinaryWriter(fstream);
...(略)
bw.Write(width + ' ' + height+'\n');
bw.Write(255);
とすればいけましたが、(というか、こうしないといけませんが)
データ部で
bw.Write(val);
とすると、valが文字列として書き込まれてしまいます。
bw.Write(val.ToString());
として実行しても結果が変わらないことから、わかると思います。
今の場合、画素値は明らかに0~255なので、byteに収まる値なので、
bw.Write((byte)val);
単純にキャストするのが正解です。
bw.Write(BitConverter.GetBytes(val));
ではうまくいきません。intは32ビットなのでbyte[4]に変換されてしまいます。

stringの文字数を書き込むんじゃない!

意外と「P5」を書き込むのにコケます。
bw.Write("P5");
と普通に書き込むと、実際には「02P5」をエンコードしたものが書き込まれてしまいます。
Encoding.Unicode.GetBytesでもうまくいきません。これだと一文字おきに「01」(1文字であることを表すバイト)が挿入されてしまい、さらにたちの悪いことになります。
ただ、これを
bw.Write('P');
bw.Write('5');
とすればうまくいきます。ここからヒントを得るならば、一般にstring型の変数strを書き込む
暫定的な正解は以下のようなもののようです。
for(int i = 0; i < str.Length; i++) bw.Write(str[i]);
記事メニュー
最近更新されたスレッド
ウィキ募集バナー