轉載:https://bbs.csdn.net/topics/360165636 3樓
1.先把較大的圖片,轉換成BMP(假定是12 x 12),沒點24bits(RGB各一個byte):
。 。 。 。 。 。 。 。 。 。 。 。
。 。 。 。 。 。 。 。 。 。 。 。
。 。 。 。 。 。 。 。 。 。 。 。
。 。 。 。 。 。 。 。 。 。 。 。
。 。 。 。 。 。 。 。 。 。 。 。
。 。 。 。 。 。 。 。 。 。 。 。
。 。 。 。 。 。 。 。 。 。 。 。
。 。 。 。 。 。 。 。 。 。 。 。
。 。 。 。 。 。 。 。 。 。 。 。
。 。 。 。 。 。 。 。 。 。 。 。
。 。 。 。 。 。 。 。 。 。 。 。
。 。 。 。 。 。 。 。 。 。 。 。
假定你要讓它變成2 x 2的圖像,你可以將上面的點陣分成2 x 2個 6 x 6的點陣。
針對每個6 x 6的點陣,把所有點的R、G、B的值加起來,分別得到sum_R、sum_G和sum_B,那么得到
點的顏色值就是(sum_R/36, sum_G/36, sum_B/36)
這樣以來,36個點就縮小為一個點了。
2.
位圖文件可看成由4個部分組成:位圖文件頭(bitmap-file header)、位圖信息頭(bitmap-information header)、彩色表(color table)和定義位圖的字節(位圖數據,即圖像數據,Data Bits 或Data Body)陣列
位圖文件頭包含有關於文件類型、文件大小、存放位置等信息,在Windows 3.0以上版本的位圖文件中用BITMAPFILEHEADER結構來定義:
typedef struct tagBITMAPFILEHEADER { /* bmfh */ UINT bfType; DWORD bfSize; UINT bfReserved1; UINT bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER;
其中:
bfType
說明文件的類型.(該值必需是0x4D42,也就是字符'BM')
注意:查ascii表B 0x42,M0x4d,bfType為兩個字節,B為low字節,M為high字節所以bfType=0x4D42,而不是0x424D.
bfSize: 說明文件的大小,用字節為單位
bfReserved1: 保留,必須設置為0
bfReserved2:保留,必須設置為0
bfOffBits:說明從文件頭開始到實際的圖象數據之間的字節的偏移量。
位圖信息用BITMAPINFO結構來定義,它由位圖信息頭(bitmap-information header)和彩色表(color table)組成,前者用BITMAPINFOHEADER結構定義,后者用RGBQUAD結構定義。
BITMAPINFO結構具有如下形式:
typedef struct tagBITMAPINFO { /* bmi */ BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[1]; } BITMAPINFO;
bmiHeader
說明BITMAPINFOHEADER結構,其中包含了有關位圖的尺寸及位格式等信息
bmiColors
說明彩色表RGBQUAD結構的陣列,其中包含索引圖像的真實RGB值。
BITMAPINFOHEADER結構包含有位圖文件的大小、壓縮類型和顏色格式,其結構定義為:
typedef struct tagBITMAPINFOHEADER { /* bmih */ DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER;
biSize
說明BITMAPINFOHEADER結構所需要的字數。注:這個值並不一定是BITMAPINFOHEADER結構的尺寸,它也可能是sizeof(BITMAPV4HEADER)的值,或是sizeof(BITMAPV5HEADER)的值。這要根據該位圖文件的格式版本來決定,不過,就現在的情況來看,絕大多數的BMP圖像都是BITMAPINFOHEADER結構的(可能是后兩者太新的緣故吧:-)。
biWidth
說明圖象的寬度,以象素為單位
biHeight
說明圖象的高度,以象素為單位。注:這個值除了用於描述圖像的高度之外,它還有另一個用處,就是指明該圖像是倒向的位圖,還是正向的位圖。如果該值是一個正數,說明圖像是倒向的,如果該值是一個負數,則說明圖像是正向的。大多數的BMP文件都是倒向的位圖,也就是時,高度值是一個正數。(注:當高度值是一個負數時(正向圖像),圖像將不能被壓縮(也就是說biCompression成員將不能是BI_RLE8或BI_RLE4)。
biPlanes
為目標設備說明位面數,其值將總是被設為1
biBitCount
說明比特數/象素,其值為1、4、8、16、24、或32
biCompression
說明圖象數據壓縮的類型。其值可以是下述值之一:
BI_RGB:沒有壓縮;
BI_RLE8:每個象素8比特的RLE壓縮編碼,壓縮格式由2字節組成(重復象素計數和顏色索引);
BI_RLE4:每個象素4比特的RLE壓縮編碼,壓縮格式由2字節組成
BI_BITFIELDS:每個象素的比特由指定的掩碼決定。
biSizeImage
說明圖象的大小,以字節為單位。當用BI_RGB格式時,可設置為0
biXPelsPerMeter
說明水平分辨率,用象素/米表示
biYPelsPerMeter
說明垂直分辨率,用象素/米表示
biClrUsed
說明位圖實際使用的彩色表中的顏色索引數(設為0的話,則說明使用所有調色板項)
biClrImportant
說明對圖象顯示有重要影響的顏色索引的數目,如果是0,表示都重要。
彩色表定位
應用程序可使用存儲在biSize成員中的信息來查找在BITMAPINFO結構中的彩色表,如下所示:
pColor = ((LPSTR) pBitmapInfo + (WORD) (pBitmapInfo->bmiHeader.biSize))
下面的代碼生成一個BMP格式的圖片的縮略圖。原圖必須大於新圖。
#define _CRT_SECURE_NO_WARNINGS #include<windows.h> #include<stdio.h> #include<assert.h> #include<iostream> using namespace std; #define NEWWIDTH 380 //新圖寬度 #define NEWHEIGHT 310 //新圖高度 //--------------------------------------------------Rothstein---------------------------------------------------------- class Rothstein { public: Rothstein(int p, int q); int operator[] (int i) { return myData[i]; } void Permute(); void PrintData(); ~Rothstein(); private: char *myData; int myP, myQ; }; Rothstein::Rothstein(int p, int q) { myP = p; myQ = q; myData = new char[p]; if (p <= q) { memset(myData, 1, p); return; } char *ptr = myData; int diff = p - q; int curr = q; for (int i = 0; i < p; i++) //if we want to permute the code, we need <<1 { if (curr < p) { *ptr = 0; curr += q; } else { *ptr = 1; curr -= diff; } ptr++; } } void Rothstein::Permute() { int temp = myData[0]; for (int i = 0; i < myP - 1; i++) myData[i] = myData[i + 1]; myData[myP - 1] = temp; } void Rothstein::PrintData() { for (int i = 0; i < myP; i++) { cout << myData[i] << " "; } cout << "\n"; } Rothstein::~Rothstein() { delete myData; } //--------------------------------------------------Rothstein---------------------------------------------------------- //--------------------------------------------------RowRothstein---------------------------------------------------------- class RowRothstein { public: RowRothstein(int largerSize, int bpp); //increment according to byte per pixel int operator[] (int i) { return myData[i]; } void PrintData(); private: int myData[NEWWIDTH]; }; RowRothstein::RowRothstein(int largerSize, int bpp) { Rothstein rot(largerSize, NEWWIDTH); int j = 0; int oldData = 0; for (int i = 0; i < largerSize; i++) { if (rot[i]) { myData[j++] = (i - oldData)*bpp; //increment in bytes per pixel * number of pixels oldData = i; } } } void RowRothstein::PrintData() { for (int i = 0; i < NEWWIDTH; i++) { cout << myData[i] << "\t"; } cout << "\n"; } //--------------------------------------------------RowRothstein---------------------------------------------------------- //--------------------------------------------------ColRothstein---------------------------------------------------------- class ColRothstein { public: ColRothstein(int largerSize, int bpl); //increment according to byte perl line int operator[] (int i) { return myData[i]; } void PrintData(); private: int myData[NEWHEIGHT]; }; ColRothstein::ColRothstein(int largerSize, int bpl) { Rothstein rot(largerSize, NEWHEIGHT); int j = 0; int oldData = 0; for (int i = 0; i < largerSize; i++) { if (rot[i]) { myData[j++] = (i - oldData) * bpl; //increment by number of lines * bytes per line oldData = i; } } } void ColRothstein::PrintData() { for (int i = 0; i < NEWHEIGHT; i++) { cout << myData[i] << "\t"; } cout << "\n"; } //--------------------------------------------------ColRothstein---------------------------------------------------------- BYTE* bits = NULL; BYTE* newbits = NULL; FILE* file = NULL; BITMAPFILEHEADER bf;//位圖文件頭 unsigned newwidth, newheight, newimagesize, newbfsize; unsigned bmiSize; unsigned imageSize; int bpp, bpl; RowRothstein *rotRow; ColRothstein *rotCol; struct { BITMAPINFOHEADER bmiHeader;//包含了有關位圖的尺寸及位格式等信息 RGBQUAD bmiColors[256];//說明彩色表RGBQUAD結構的陣列,其中包含索引圖像的真實RGB值 } bmi;//位圖信息 void InitDevice() { newwidth = NEWWIDTH; newheight = NEWHEIGHT; //-------byte per pixel 3 original image byte per line 800 x 3 = 2400 bpp = 3; bpl = bmi.bmiHeader.biWidth * bpp; rotRow = new RowRothstein(bmi.bmiHeader.biWidth, bpp); rotCol = new ColRothstein(bmi.bmiHeader.biHeight, bpl); } void ResizeImage(unsigned char* src, unsigned char* dst) { unsigned char* oldp; //pointer to the pix in the old image int oldcol = 0; for (int row = 0; row < NEWHEIGHT; row++) { src += (*rotCol)[row]; oldp = src; for (int col = 0; col < NEWWIDTH;) { //unroll 10 times; oldp += (*rotRow)[col++]; memcpy(dst, oldp, bpp); dst += bpp; oldp += (*rotRow)[col++]; memcpy(dst, oldp, bpp); dst += bpp; oldp += (*rotRow)[col++]; memcpy(dst, oldp, bpp); dst += bpp; oldp += (*rotRow)[col++]; memcpy(dst, oldp, bpp); dst += bpp; oldp += (*rotRow)[col++]; memcpy(dst, oldp, bpp); dst += bpp; oldp += (*rotRow)[col++]; memcpy(dst, oldp, bpp); dst += bpp; oldp += (*rotRow)[col++]; memcpy(dst, oldp, bpp); dst += bpp; oldp += (*rotRow)[col++]; memcpy(dst, oldp, bpp); dst += bpp; oldp += (*rotRow)[col++]; memcpy(dst, oldp, bpp); dst += bpp; oldp += (*rotRow)[col++]; memcpy(dst, oldp, bpp); dst += bpp; } } } void LoadBMP(char* filename) { if (!(file = fopen(filename, "rb"))) { goto done; } if (fread(&bf, 1, sizeof(bf), file) != sizeof(bf)) { goto done; } if (bf.bfType != *(WORD*) "BM") {//判斷是否是bmp文件,bmp文件位圖文件頭的bfType一定是"BM"(0x4D42) goto done; } bmiSize = bf.bfOffBits - sizeof(bf);//bfOffBits:從文件頭開始到實際的圖象數據之間的字節的偏移量 if (bmiSize > sizeof(bmi)) { goto done; } if (fread(&bmi, 1, bmiSize, file) != bmiSize) { goto done; } //biWidth:圖像寬度,以像素為單位 /* biHeight:圖象的高度,以象素為單位。如果該值是一個正數,說明圖像是倒向的,如果該值是一個負數,則說明圖像是正向的。 當高度值是一個負數時(正向圖像),圖像將不能被壓縮 */ //biBitCount:說明比特數/象素,其值為1、4、8、16、24、或32 imageSize = (bmi.bmiHeader.biWidth * bmi.bmiHeader.biBitCount / 8 + 3 & ~3) * bmi.bmiHeader.biHeight; bits = new BYTE[imageSize]; if (fread(bits, 1, imageSize, file) != imageSize) { goto done; } assert(bmi.bmiHeader.biHeight >= NEWHEIGHT);//原圖片應該比縮略圖大 assert(bmi.bmiHeader.biWidth >= NEWWIDTH);//原圖片應該比縮略圖大 cout << "image size is " << imageSize << "\n"; cout << "color is " << bmi.bmiHeader.biBitCount << "\n"; cout << "width is " << bmi.bmiHeader.biWidth << " height is " << bmi.bmiHeader.biHeight << "\n"; done: if (file) { fclose(file); } } void ProcessBMP(char* filename) { newimagesize = (newwidth* bmi.bmiHeader.biBitCount / 8 + 3 & ~3)* newheight; newbits = new BYTE[newimagesize]; int bytes_per_line = bmi.bmiHeader.biBitCount / 8 * bmi.bmiHeader.biWidth + 3 & ~3; ResizeImage((unsigned char*)bits, (unsigned char*)newbits); int filesize = sizeof(bf)+bmiSize + newimagesize; bf.bfSize = filesize; bmi.bmiHeader.biWidth = newwidth; bmi.bmiHeader.biHeight = newheight; bmi.bmiHeader.biSizeImage = newimagesize; if (!(file = fopen(filename, "wb"))) { goto done; } if (fwrite(&bf, 1, sizeof(bf), file) != sizeof(bf)) { goto done; } if (fwrite(&bmi, 1, bmiSize, file) != bmiSize) { goto done; } if (fwrite(newbits, 1, newimagesize, file) != newimagesize) { goto done; } done: if (file) { fclose(file); } if (bits) { delete[] bits; } if (newbits) { delete[] newbits; } if (rotRow) { delete rotRow; } if (rotCol) { delete rotCol; } } int main(int argc, char* argv[]) { char* infile; char* outfile; { infile = "test.bmp"; outfile = "test2.bmp"; LoadBMP(infile); InitDevice(); ProcessBMP(outfile); } system("pause"); return 0; }
