鐵之狂傲
標題:
C++讀取BMP圖檔,心得教學。
[列印本頁]
作者:
magicalloveshe
時間:
07-2-27 00:49
標題:
C++讀取BMP圖檔,心得教學。
要讀取檔案,就我從不會到會的經驗來看,有兩個重點
1.用fstream讀取檔案的方式。
2.了解要讀取的檔案的格式,這點比較重要。
#include <fstream>
//開檔
char Name[]=“01.bmp”; //檔名。注意:這邊的NAME就是下一行的NAME,也就是要讀進去的檔案名稱,這名稱有包括副檔名。
file.open(Name,參數);
//讀檔
file.read(變數,長度);//變數:將讀進去的資料以"變數"這麼名稱儲存。長度:要讀多少長度進去。
例如:
file.read(line1,3);//這行的意思就是,讀進三個位元組的長度,將這三個位元組儲存在名稱為line1的陣列裡面。當然了,前面要先宣告一個名稱為line1的陣列才行阿。(char line1[32];)
//寫檔
file2.write(變數,長度);
例如:file.write(line1,3);//將陣列line1裡面的內容前面三個寫出到檔案裡面,詳細請見下面那一個完整的code。
複製代碼
這就是基本的fstream讀檔方式
因為在寫code時,你必須要知道這個檔案的哪幾個資料代表什麼,所以一定要先找出這個檔的組成結構。
之前有人回覆給我這個網址
http://blog.pixnet.net/crazycat1130/post/1345538
內容不錯,必看!
除此網站之外,我們助教給我們的PDF也很詳細,也必看!
http://myweb.ncku.edu.tw/~f7495223/BMP_PDF.rar
附上一些fstream的開檔基本用法
開啟檔案時需使用open()這個函式。其格式如下。
file.open(Name,nMode);
ios::app:檔案開啟後,檔案指位器直接跳到末端位置,輸入的資料將接在檔案後面。。
􀂄ios::in:以輸入的方式處理檔案,這是ifstream的內定值。
􀂄ios::out:以輸出的方式處理檔案,這是ofstream的內定值。
􀂄ios::trunc:如果檔案已經存在,則內容將被清除。
􀂄ios::nocreate:如果檔案不存在,則會有錯誤訊息。
􀂄ios::noreplace:如果檔案已經存在,則會有錯誤訊息。
􀂄ios::binary:以二進位的形式來處理檔案。
所以整行可以寫成這樣
file.open(Name,ios::in||ios::binary);
複製代碼
聽同學說處理非純文字的檔案都要加上ios::binary
上面的code"簡化"自助教給的PDF,因為那PDF裡面我看不懂的地方沒有PO上來。
在了解檔案結構之後,建議使用Ultra edit比對之前看到的教學,你會更清楚那是什麼意思!
Ultra edit下載:
http://toget.pchome.com.tw/intro/business_wordprocessing/286.html
我覺得最重要的觀念是,「PDF中所寫的圖片資訊,在Ultra edit中,就是按照PDF中介紹的順序一路排列下來的。」(只有我覺得重要吧,同學都很直接這樣想.....)
意思就是,
Ultra edit看到的一堆碼,前兩組就是代表檔案形式,接下來四組代表檔案大小,再來兩組是保留區‧‧‧以此類堆。
知道那些碼代表什麼之後,你還要會解讀!
例如:Ultra edit中顯示BMP圖檔最開頭兩組是42 4D,在ASCII(阿斯KEY)中,42=B,4D=M。
再來後兩組是大小的資訊,以一張17462位元組的BMP圖檔為例,第三跟第四組資訊為,36 44。
然後我們開啟小算盤,將它改為工程用的模式(檢視→工程型),在16進位下輸入3644,在轉換到10進位看,卻發現他不是17462。
可是當我們將16進位中的數字改為4436,再將它轉換到10進位,沒錯!它變成17462了。為什麼要從後面開始讀,這我也不知道,反正事實上就是這樣子,而這對我們寫code不會有什麼影響,只是寫出來讓大家輕鬆一下而已。
註:有時會有有一種很詭異的情況:「圖片大小跟儲存的資訊不一樣」。
例如原本我從助教那邊拿到的作業圖片是一張128*128的圖片,整張圖片加上一些檔頭資訊後,這張圖片按照36 44的計算,大小應該是17462位元組,但事實上。剛從助教那邊拿過來時他的大小是17464位元組(右鍵內容看到的),莫名奇妙多出兩個位元組。
原因不明,但是在將圖片用小畫家開啟,隨便做個動作然後復原它,然後另存新檔,檔案大小就變成了17462了(右鍵內容看到的)。
當它的大小是17464時,用Ultra edit看裡面的大小資訊,依然是36 44。
上面就夠讓一個新手頭痛啦!
再來就是整個code怎麼做了。
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
#include <fstream>
using std::fstream;
using std::ios;
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef long LONG;
void main(){
fstream file;
int i,j;
char fileName[32], RGBQUAD[4][256], PIXEL[128][128],temp[128][128];
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
//將資料從檔案輸入到記憶體
cout << "Open FileName: ";
cin >> fileName;
file.open(fileName, ios::in|ios::binary);
file.read((char*)&bfType, sizeof(WORD));
file.read((char*)&bfSize, sizeof(DWORD));
file.read((char*)&bfReserved1, sizeof(WORD));
file.read((char*)&bfReserved2, sizeof(WORD));
file.read((char*)&bfOffBits, sizeof(DWORD));
file.read((char*)&biSize, sizeof(DWORD));
file.read((char*)&biWidth, sizeof(LONG));
file.read((char*)&biHeight, sizeof(LONG));
file.read((char*)&biPlanes, sizeof(WORD));
file.read((char*)&biBitCount, sizeof(WORD));
file.read((char*)&biCompression, sizeof(DWORD));
file.read((char*)&biSizeImage, sizeof(DWORD));
file.read((char*)&biXPelsPerMeter, sizeof(LONG));
file.read((char*)&biYPelsPerMeter, sizeof(LONG));
file.read((char*)&biClrUsed, sizeof(DWORD));
file.read((char*)&biClrImportant, sizeof(DWORD));
file.read(RGBQUAD[0], sizeof(RGBQUAD));
file.read(PIXEL[0], sizeof(PIXEL));
file.close();
//顯示檔案資訊
cout << "FILE_HEADER\n"
<< "bfType=\t\t" << bfType << '\n'
<< "bfSize=\t\t" << bfSize << '\n'
<< "bfReserved1=\t" << bfReserved1 << '\n'
<< "bfReserved2=\t" << bfReserved2 << '\n'
<< "bfOffBits=\t" << bfOffBits << "\n\n"
<< "INFO_HEADER\n"
<< "biSize=\t\t" << biSize << '\n'
<< "biWidth=\t" << biWidth << '\n'
<< "biHeight=\t" << biHeight << '\n'
<< "biPlanes=\t" << biPlanes << '\n'
<< "biBitCount=\t" << biBitCount << '\n'
<< "biCompression=\t" << biCompression << '\n'
<< "biSizeImage=\t" << biSizeImage << '\n'
<< "biXPelsPerMeter=" << biXPelsPerMeter << '\n'
<< "biYPelsPerMeter=" << biYPelsPerMeter << '\n'
<< "biClrUsed=\t" << biClrUsed << '\n'
<< "biClrImportant=\t" << biClrImportant << "\n\n";
//將圖片資訊暫存到TEMP裡面
for(i=127;i>=0;i--){
for(j=127;j>=0;j--){
temp[i][j]=PIXEL[i][j];
}
}
//將資訊反轉180度
for(i=0;i<=127;i++){
for(j=0;j<=127;j++){
PIXEL[127-i][127-j]=temp[i][j];
}
}
//將資料從記憶體輸出到檔案
cout << "輸入旋轉後儲存的名稱:\t";
cin >> fileName;
file.open(fileName, ios::out|ios::binary);
file.write((char*)&bfType, sizeof(WORD));
file.write((char*)&bfSize, sizeof(DWORD));
file.write((char*)&bfReserved1, sizeof(WORD));
file.write((char*)&bfReserved2, sizeof(WORD));
file.write((char*)&bfOffBits, sizeof(DWORD));
file.write((char*)&biSize, sizeof(DWORD));
file.write((char*)&biWidth, sizeof(LONG));
file.write((char*)&biHeight, sizeof(LONG));
file.write((char*)&biPlanes, sizeof(WORD));
file.write((char*)&biBitCount, sizeof(WORD));
file.write((char*)&biCompression, sizeof(DWORD));
file.write((char*)&biSizeImage, sizeof(DWORD));
file.write((char*)&biXPelsPerMeter, sizeof(LONG));
file.write((char*)&biYPelsPerMeter, sizeof(LONG));
file.write((char*)&biClrUsed, sizeof(DWORD));
file.write((char*)&biClrImportant, sizeof(DWORD));
file.write(RGBQUAD[0], sizeof(RGBQUAD));
file.write(PIXEL[0], sizeof(PIXEL));
file.close();
複製代碼
因為我要顯示檔案資訊
所以中間那一段比較複雜
一般要做特效的話,不必將中間檔案資訊的地方每一段都讀出來,直接將它讀做一個headfile就可以了。
要讀取的圖檔記得要放在你的專案所儲存的資料夾。
差不多就這樣吧。拜拜
作者:
magicalloveshe
時間:
07-2-27 00:51
這是我原本發在微風的東西
現在轉過來
應該可以讓C++新手知道學到的東西有這種很好玩的應用方法
作者:
青雲
時間:
09-11-14 05:11
不推不是人啊
作者:
waync
時間:
10-3-6 18:05
程式寫的不錯,推一下
另有二點建議
1. 讀入BMP檔頭資訊的部份可以研究一下stuct的用法
2. 看來這程式是假設開的檔案是BMP,不是BMP的情況可以加點檢查,避免出錯
歡迎光臨 鐵之狂傲 (https://gamez.com.tw/)