C語言讀取BMP數字影象
阿新 • • 發佈:2018-12-13
// 資料型別說明: // WORD:16位無符號短整形,佔2個位元組 // DWORD:32位無符號短整形,佔4個位元組 // LONG:有符號32位整形,佔4個位元組 // RGBQUAD:用於定義調色盤陣列元素的型別 // LPBITMAPINFOHEADER:點陣圖資訊頭(BITMAPINFOHEADER)的指標 // LOGPALETTE:定義了一個邏輯調色盤 // LPRGBQUAD:指向RGBQUAD結構的指標 // HPALETTE:調色盤控制代碼 // HDC:裝置控制代碼 // HLOCAL:區域性記憶體控制代碼 // HWND:視窗控制代碼 // HFILE:檔案控制代碼 // HBITMAP:點陣圖控制代碼 // HGLOBAL:表示一個記憶體塊控制代碼,GlobalAlloc分配,GlobalLock讀取 // LPSTR:一種字串資料型別,指向以‘\0’結尾的32位ANSI字元陣列指標 // LPCWSTR:一個紙箱unicode編碼字串的32位指標,指向字串是wchar型,而不是char型 // BITMAPFILEHEADER:點陣圖檔案頭結構體 // BITMAPINFOHEADER:點陣圖資訊頭結構體 //************ 關於檔案的操作:https://blog.csdn.net/virtualdesk/article/details/4379704 ************ // _lopen:以二進位制形式開啟指定的檔案 // lread: 將檔案中的資料讀入記憶體緩衝區 // lwrite:將資料從記憶體緩衝區寫入一個檔案 // lcreat:建立一個檔案 #include <stdio.h> #include <Windows.h> #define WIDTHBYTES(i) ((i+31)/32*4) BITMAPFILEHEADER bf; BITMAPINFOHEADER bi; HBITMAP hBitmap; HPALETTE hPalette; HGLOBAL hImgData; DWORD NumColors; DWORD LineBytes; // 每行的位元組數 int xOffset = 0, yOffset = 0; BOOL LoadBmpFile(HWND hWnd, char *BmpFileName) { HFILE hf; // 檔案控制代碼 LPBITMAPINFOHEADER lpImgData; // 資訊頭指標 LOGPALETTE *pPal; // 指向調色版的指標 LPRGBQUAD lpRGB; // 指向RGBQUAD結構的指標 HPALETTE hPrePalette; // 儲存裝置中調色盤 HDC hDc; // 裝置控制代碼 HLOCAL hPal; // 儲存調色盤的區域性記憶體控制代碼 DWORD ImgSize; // 實際的影象資料佔用的位元組數 DWORD i; BmpFileName = "G:\c語言影象處理\T102\T102\0.bmp"; if ((hf = _lopen(BmpFileName, OF_READ)) == HFILE_ERROR) { MessageBox(hWnd, (LPCWSTR)"File not found", (LPCWSTR)"ERROR Message", MB_OK | MB_ICONEXCLAMATION); return FALSE; } _lread(hf, (LPSTR)&bf, sizeof(BITMAPFILEHEADER)); // 將BITMAPFILEHEADER結構從檔案中讀出,寫到bf中 _lread(hf, (LPSTR)&bi, sizeof(BITMAPINFOHEADER)); // 將BITMAPINFOHEADER結構從檔案中讀出,寫到bf中 LineBytes = (DWORD)GDI_WIDTHBYTES(bi.biWidth*bi.biBitCount); // 每行的位元組數 ImgSize = (DWORD)LineBytes*bi.biHeight; // 實際的影象資料佔用的位元組數 if (bi.biClrUsed != 0) // 調色盤陣列中實際的顏色數 NumColors = (DWORD)bi.biClrUsed; else { switch (bi.biBitCount) { case 1: NumColors = 2; break; case 4: NumColors = 16; break; case 8: NumColors = 256; break; case 24: NumColors = 0; break; default: MessageBox(hWnd, (LPCWSTR)"Invalid Color Numbers", (LPCWSTR)"Error Message", MB_OK | MB_ICONEXCLAMATION); _lclose(hf); return FALSE; } if (bf.bfOffBits != (DWORD)(NumColors*sizeof(RGBQUAD) // 計算出的偏移量與實際的偏移量不符,則顏色數出錯 +sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER))) { MessageBox(hWnd, (LPCWSTR)"Invalid Color Numbers", (LPCWSTR)"Error Message", MB_OK | MB_ICONEXCLAMATION); _lclose(hf); return FALSE; } bf.bfSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER) +NumColors*sizeof(RGBQUAD)+ImgSize; // 分配記憶體,大小為BITMAPINFOHEADER結構長度+調色盤+實際點陣圖 hImgData = GlobalAlloc(GHND, (DWORD)(sizeof(BITMAPINFOHEADER)+NumColors*sizeof(RGBQUAD)+ImgSize)); if (hImgData == NULL) { _lclose(hf); return FALSE; } lpImgData = (LPBITMAPINFOHEADER)GlobalLock(hImgData); // lpImgData指向該記憶體區 _llseek(hf, sizeof(BITMAPFILEHEADER), SEEK_SET); // 檔案指標重新定位到LPBITMAPINFOHEADER開始處 _hread(hf, (char*)lpImgData, (long)sizeof(BITMAPINFOHEADER)+(long)NumColors*sizeof(RGBQUAD)+ImgSize); // 將檔案內容讀入lpImgData _lclose(hf); if (NumColors != 0) // 顏色數不為0,說明用到了調色盤 { hPal = LocalAlloc(LHND, sizeof(LOGPALETTE)+NumColors*sizeof(PALETTEENTRY)); // 為邏輯調色盤分配記憶體 pPal = (LOGPALETTE*)LocalLock(hPal); // 指標pPal指向記憶體區 pPal->palNumEntries = NumColors; // 邏輯調色盤結構頭 pPal->palVersion = 0x300; lpRGB = (LPRGBQUAD)((LPSTR)lpImgData + (DWORD)sizeof(BITMAPINFOHEADER)); // lpRGB指向調色盤開始的位置 for (i = 0; i < NumColors; ++i) // 填寫資料 { pPal->palPalEntry[i].peRed = lpRGB->rgbRed; pPal->palPalEntry[i].peGreen = lpRGB->rgbGreen; pPal->palPalEntry[i].peBlue = lpRGB->rgbBlue; pPal->palPalEntry[i].peFlags = (BYTE)0; lpRGB++; } hPalette = CreatePalette(pPal); // 產生邏輯調色盤 LocalUnlock(hPal); // 釋放區域性記憶體 LocalFree(hPal); // 釋放區域性記憶體 } hDc = GetDC(hWnd); // 獲取上下文控制代碼 if (hPalette) { hPrePalette = SelectPalette(hDc, hPalette, FALSE);//將新的邏輯調色盤選入 DC,將舊的邏輯調色盤控制代碼儲存在//hPrevPalette RealizePalette(hDc); } // 產生點陣圖控制代碼 hBitmap = CreateDIBitmap(hDc, (LPBITMAPINFOHEADER)lpImgData, (LONG)CBM_INIT, (LPSTR)lpImgData + sizeof(BITMAPINFOHEADER)+NumColors*sizeof(RGBQUAD), (LPBITMAPINFO)lpImgData, DIB_RGB_COLORS); // 將原來的調色盤(如果有的話)選入裝置上下文控制代碼 if (hPalette && hPrePalette) { SelectPalette(hDc, hPrePalette, FALSE); RealizePalette(hDc); } ReleaseDC(hWnd, hDc); // 釋放裝置上下文 GlobalUnlock(hImgData); // 解鎖記憶體區 return TRUE; } }