作者tropical72 (藍影)
看板C_and_CPP
標題Re: [問題] 新手讀bmp 的每點rgb
時間Fri Aug 5 20:01:22 2011
※ 引述《pigcat1315 (還是朋友?)》之銘言:
: 問題(Question):
: 24位元的bmp
: 因為我用fstream 來寫開讀檔 跟大家用file = =a 不太一樣
: 所以標頭讀完後 = 口= 我就不知道也怎讀取rgb了
我以為,你會讀 bmp header 後,應該也會讀 rgb 了...
: int open_file()
: {
: bmpfileheader fhd;
: bmpinfoheader ihd;
: RGB color;
: fstream file ; //宣告fstream物件
: file.clear();
: file.open("3.bmp",ios::in|ios::binary );
: // file head 的部分都省略
: //以上info的讀取也省略
: file.read((char*)&ihd.bmpColorImportant,4);
我其實很好奇一點:你是不是沒用過 PSPad / UltraEditor 去看 hex mode ?
00000000h: A4 6B B0 A8 A5 D5 A4 63 A4 66 A6 43 0D 0A A4 53 ; xxxxxxxxxxxx..又
00000010h: AD 6E A4 40 AD D3 A4 48 B9 4C B1 A1 A4 48 B8 60 ; 要一個人過情人節
00000020h: 2C 20 47 47 ; , GG
這段你看得出有什麼關聯性嗎?如果會看的話,我建議先用上述其中一個先去觀查,
會比較有感覺。
以下只做 拋磚引玉 之效
(說白了,就是沒什麼神奇的技巧在裡面)
-----
在讀 bmp 時,若堅持要用 iofstream object,我其實比較建議用 ifstream,
下面做一些簡單的轉換 (聲明,這只是在「功能上」有相似,但整體運作概念不同),
變數 fp、fin 都是一直延用
-----
1. 開啟檔案
/* in c */
FILE *fp = fopen("1.bmp", "rb");
if(fp==NULL) {
printf("open fail.\n");
exit(1);
}
/* in c++ */
ifstream fin("1.bmp", iso::in | iso::binary);
if(!fin) {
cout << "open fail.\n";
exit(1);
}
-----
2. 讀單一字元
/* in c */
char ch = fgetc();
/* in c++ */
char ch = fin.get();
-----
3. 讀一個 block
這裡,假設要直接讀此 bmp filesize,
是從 02h 開始,佔 4 bytes
unsigned file_size;
/* in c */
fseek(fp, 0x02, SEEK_SET); // start position, want to set
fread(&file_size, sizeof(byte), 4);
// fread(&file_size, sizeof(unsigned), 1); // "maybe" worst.
/* in c++ */
fin.seekg(0x02);
fin.read((char*)&file_size, 4);
----
4. 關檔
/* in c */
fclose(fp); /* eof 將被自動清除 */
/* in c++ */
fin.close();
fin.clear(); /* 清除所有 flag, 含 eof */
----
基本上讀 bmp 用上面幾個轉換就可以。至於你說要讀 rgb 的話,可以,
下面程式碼沒試過,推斷應可類似這麼做
typedef struct tagRGB{
byte B;
byte G;
byte R;
byte reserve;
}RGB;
/* 給 buffer 大小 */
RGB **raw_data = new RGB*[height];
for(size_t i=0; i!=height; ++i) raw_data[i] = new RGB[width];
/* 開始讀 RGB */
fin.seekg(0x36); /* start from 0x36(54)*/
for(size_t i=0; i!=height; ++i) /* 把第 i */
fin.read((char*)raw_data[i], width*3);
這裡是先假設你已從 header 讀出 width、heigh 之做法,
每次都一列一列讀進來,
fin.read(
(char*)raw_data[i], /* 將第 i 列之 raw_data 讀入 */
width*3 /* 每一列有 width 個 pixel, 一個 pixel 有 bgr,3bytes */
);
這裡會有更好的做法,但若對 陣列轉換 (一維 <----> 二維) 沒很熟的話,
就暫用這方法吧。
------------
你看到一些很莫名的 code,
那是因為 bmp 存檔之後,可能一些軟體「不小心」又多塞了一些 garbge 進去,
也因為這些 garbge ,會使得 bmp header information 變得不可靠。如
實際 filelength 與 bmp information filelength 不合;
還有一些「對齊」問題 (有些要對,有些不用對【應說是必對】);
若單純寫 24bits bmp,這不難;
要寫完「完整的 bmp」,要真正完整,就把 spec K 完 (我知道很無聊,所以沒 K );
要快速交差,直接研究別人的 code (當然是要挑過),
看他們到底處理了哪些問題。
結束前提醒一件事,是可以用 fin.get() 一個一個慢慢讀,
但如果整份 rgb raw_data 都用 fin.get() 這.. 效能有待加強。
fin.seekg / fin.read 部份建議再開一份 test project 去摸熟,
大部份都在摸這二隻函式,其它的 domain know how... 我不想代 K Spec XD
------------
以上,供參閱。
--
YouLoveMe() ? LetItBe() : LetMeFree();
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 180.177.78.41
※ 編輯: tropical72 來自: 180.177.78.41 (08/05 20:18)
推 pigcat1315:感謝大大整理QQ 08/05 21:07
→ angleevil:你的例子有怨念.不過謝謝你.因為我也不會rgb 08/05 21:25