hoge diary - July 17, 2007

[プログラミング] PGM ファイルの書き出し in Windows

Windows 上でプログラムを書いていて,24-bit 画像のピクセルデータを std::vector<BYTE> 上に保持し,それを PGM (P5; バイナリ形式) 形式で手っ取り早くファイルに書き出そうと思い,以下のコード片を書きました.

std::vector<BYTE> pixel_data;
...

std::ofstream out("temp.pgm");
out << "P5\n" << width << " " << height << "\n255\n";          // width と height はそれぞれ画像の幅と高さ
for (std::vector<BYTE>::iterator it = pixel_data.begin(); it != pixel_data.end(); ++it)
{
  char p = *it;
  out.write(&p, 1);
}

これが見事に大はまり.出力した PGM ファイルを IrfanView で見ると... 1 ピクセル横にずれるのです.原因がさっぱり分からず数時間たっぷり悩んでいました.

悩みながら,PGM (P5) の代わりに PPM (P6) で書き込むと,RGB の成分ずれが起こったので,今回の原因に気づきました.テキストモードで書き込んでいたため LF が CR+LF に変換されていたというわけです.

以下のように,バイナリモードでファイルを開いて書き込めば万事解決.

std::vector<BYTE> pixel_data;
...

std::ofstream out("temp.pgm", std::ios::binary);
out << "P5\n" << width << " " << height << "\n255\n";          // width と height はそれぞれ画像の幅と高さ
for (std::vector<BYTE>::iterator it = pixel_data.begin(); it != pixel_data.end(); ++it)
{
  char p = *it;
  out.write(&p, 1);
}

今まで散々 LF オンリーな環境でプログラムを書いていたので,全然気づきませんでした.あー,なんて凡ミスをしてるんだろ俺.

コメント

名前(何でも可):

テキスト(http:// を含む内容は投稿できません):

トラックバック

トラックバック URI: https://www.pakunet.jp/hoge/trackback/2007071702

トラックバックはありません.

[C++] 宣言ならば値で受け渡す引数に不完全型を使っても良い

最近 C++ で pimpl イディオム(コンパイラファイアウォール)を使ってヘッダファイル間の依存関係を減らすことを(くだらないクラス型に対しても)積極的に実践しています.

pimpl は不完全型(incomplete type; 定義がなく宣言のみの型)へのポインタもしくはリファレンスが使えることを前提に成り立っているわけですが,私は不完全型はポインタもしくはリファレンスだけにしか適用できないと思い込んでました.

Exceptional C++ の 4 章を読んでいると,値渡し,あるいは値返しをする関数の宣言に不完全型が使われていました.

「え!? こんなことできるの!?」と思ってしまいました.

というのも,ポインタやリファレンスについては,指し示す先の具体的な情報を知らなくていいというのが直感で分かりますのでいいとして,これが値で受け渡す場合にも通用するとは思っていなかったのです.

思い込みとは恐ろしいものです.試しにコードを書いてみると...

// test.cc
class A;
A func();
% g++ -c test.cc
%

通りました.宣言だけなら不完全型で大丈夫のようです.

もちろん使用するには完全型である必要がありますので,以下の 2 つのコードはコンパイルエラーです.

// test1.cc
class A;
A func();    // ただの宣言
int main()
{
  A a1;             // Error. 不完全型のインスタンスを定義することはできない
  A a2 = func();    // Error. 不完全型の初期化はできない
  return 0;
}
// test2.cc
class A;
A* func1();  // ただの宣言
A func2()
{
  return *func1();    // Error. 不完全型を値返しすることはできない
}

int main()
{
  return 0;
}
% g++ -c test1.cc
test1.cc: In function `int main()':
test1.cc:8: error: aggregate `A a1' has incomplete type and cannot be defined
test1.cc:9: error: variable `A a2' has initializer but incomplete type
test1.cc:9: error: invalid use of undefined type `struct A'
test1.cc:2: error: forward declaration of `struct A'
% g++ -c test2.cc
test2.cc: In function `A func2()':
test2.cc:6: error: return type `struct A' is incomplete
test2.cc:7: confused by earlier errors, bailing out
%

ということは,これでさらにヘッダ内の #include を減らすことができる,というわけです.

C++ は全くもって複雑で,調べれば調べるほどに奥深さを感じます.今回もまた一つ勉強になりました.

コメント

名前(何でも可):

テキスト(http:// を含む内容は投稿できません):

トラックバック

トラックバック URI: https://www.pakunet.jp/hoge/trackback/2007071701

トラックバックはありません.


Valid XHTML 1.1! Valid CSS!
© 2004-2009 ぱくちゃん.
Last modified: Fri Nov 02 08:58:03 JST 2007