當初是自己要裝X,非要用c來寫信息隱藏作業,裝了X,就得付出實踐。查了好久資料,到期末才把作業交了,這里總結一下。
這道題是將真彩圖轉換為灰度圖。
- 關於BMP文件結構,這是困擾了我好久的問題,上網查了很久圖片的知識才弄明白
- BMP文件包括以下幾部分(具體結構在程序中說明):
- 位圖文件頭
- 位圖信息頭
- 調色板
- 位圖數據
- 結構體內存對齊原則對於pragma pack(n)
- 當成員大小小於n時,每個成員存儲的起始位置要從該成員大小的整數倍開始,否則從n的整數倍開始
- 成員是結構體時相對於起始偏移是以其內部最大成員為准
- 當n大於內部最大成員時,結構體的總大小是其內部最大成員的整數倍反之為n的整數倍
- 32位默認n為4,64位默認為8
- 因此在定義頭結構的時候要加上#pragma pack(1),設置以1字節為對齊方式,不然后面數據會錯位
1 /* 2 真彩圖轉換成灰度圖的改進版 3 (不把真彩圖的每個像素點放入二維矩陣,而是讀一行寫一行) 4 blog:http://www.cnblogs.com/wd1001/ 5 2015年6月2日19:04:09 6 */ 7 #include<stdio.h> 8 #include<malloc.h> 9 #include<stdlib.h> 10 /* 11 位圖頭結構 12 */ 13 #pragma pack(1) 14 typedef struct tagBITMAPFILEHEADER 15 { 16 unsigned char bfType[2];//文件格式 17 unsigned long bfSize;//文件大小 18 unsigned short bfReserved1;//保留 19 unsigned short bfReserved2; 20 unsigned long bfOffBits; //DIB數據在文件中的偏移量 21 }fileHeader; 22 #pragma pack() 23 /* 24 位圖數據信息結構 25 */ 26 #pragma pack(1) 27 typedef struct tagBITMAPINFOHEADER 28 { 29 unsigned long biSize;//該結構的大小 30 long biWidth;//文件寬度 31 long biHeight;//文件高度 32 unsigned short biPlanes;//平面數 33 unsigned short biBitCount;//顏色位數 34 unsigned long biCompression;//壓縮類型 35 unsigned long biSizeImage;//DIB數據區大小 36 long biXPixPerMeter; 37 long biYPixPerMeter; 38 unsigned long biClrUsed;//多少顏色索引表 39 unsigned long biClrImporant;//多少重要顏色 40 }fileInfo; 41 #pragma pack() 42 /* 43 調色板結構 44 */ 45 #pragma pack(1) 46 typedef struct tagRGBQUAD 47 { 48 unsigned char rgbBlue; //藍色分量亮度 49 unsigned char rgbGreen;//綠色分量亮度 50 unsigned char rgbRed;//紅色分量亮度 51 unsigned char rgbReserved; 52 }rgbq; 53 #pragma pack() 54 55 int main() 56 { 57 /*存儲RGB圖像的一行像素點*/ 58 unsigned char ImgData[3000][3]; 59 /*將灰度圖的像素存到一個一維數組中*/ 60 unsigned char ImgData2[3000]; 61 int i,j,k; 62 FILE * fpBMP,* fpGray; 63 fileHeader * fh; 64 fileInfo * fi; 65 rgbq * fq; 66 67 if((fpBMP=fopen("G:/vc6.0/work/21.bmp","rb"))==NULL) 68 { 69 printf("打開文件失敗"); 70 exit(0); 71 } 72 73 if((fpGray=fopen("G:/vc6.0/work/22.bmp","wb"))==NULL) 74 { 75 printf("創建文件失敗"); 76 exit(0); 77 } 78 79 fh=(fileHeader *)malloc(sizeof(fileHeader)); 80 fi=(fileInfo *)malloc(sizeof(fileInfo)); 81 //讀取位圖頭結構和信息頭 82 fread(fh,sizeof(fileHeader),1,fpBMP); 83 fread(fi,sizeof(fileInfo),1,fpBMP); 84 //修改頭信息 85 fi->biBitCount=8; 86 fi->biSizeImage=( (fi->biWidth*3+3)/4 ) * 4*fi->biHeight; 87 //fi->biClrUsed=256; 88 89 fh->bfOffBits = sizeof(fileHeader)+sizeof(fileInfo)+256*sizeof(rgbq); 90 fh->bfSize = fh->bfOffBits + fi->biSizeImage; 91 92 //創建調色版 93 fq=(rgbq *)malloc(256*sizeof(rgbq)); 94 for(i=0;i<256;i++) 95 { 96 fq[i].rgbBlue=fq[i].rgbGreen=fq[i].rgbRed=i; 97 //fq[i].rgbReserved=0; 98 } 99 //將頭信息寫入 100 fwrite(fh,sizeof(fileHeader),1,fpGray); 101 fwrite(fi,sizeof(fileInfo),1,fpGray); 102 fwrite(fq,sizeof(rgbq),256,fpGray); 103 //讀取RGB圖像素並轉換為灰度值 104 for ( i=0;i<fi->biHeight;i++ ) 105 { 106 for(j=0;j<(fi->biWidth+3)/4*4;j++) 107 { 108 for(k=0;k<3;k++) 109 fread(&ImgData[j][k],1,1,fpBMP); 110 } 111 for(j=0;j<(fi->biWidth+3)/4*4;j++) 112 { 113 ImgData2[j]=int( (float)ImgData[j][0] * 0.114 + 114 (float)ImgData[j][1] * 0.587 + 115 (float)ImgData[j][2] * 0.299 ); 116 } 117 //將灰度圖信息寫入 118 fwrite(ImgData2,j,1,fpGray); 119 } 120 121 free(fh); 122 free(fi); 123 free(fq); 124 fclose(fpBMP); 125 fclose(fpGray); 126 printf("success\n"); 127 return 0; 128 }
結果: