035 利用 Win32 API 來讀取/儲存 BMP 圖檔

Post date: 2015/5/12 上午 04:13:41

首先我自行定義了一個 rgb 的 structure

typedef struct sRGB

{

// 順序不可調換

unsigned char B, G, R;

} sRGB;

下面有些程式碼還可以縮減(例如調色盤整個可以幹掉),不過目前能用就好了….

因為使用 Win32 API 及其資料結構,所以記得要

#include <windows.h>

使用函式

我把外面包了 4 個函式:

  • BOOL LoadBMP(LPTSTR szFileName); // 讀取 BMP 檔案
  • COLORREF getPixel(int x, int y); // 取得 BMP 的像素
  • GetRValue(COLORREF c), GetGValue(COLORREF c), GetBValue(COLORREF c) //取得 RGB 的值
  • void FreeBMP(); // 釋放 BMP 實體
  • void SaveBMP(sRGB *data, LPCTSTR lpszFileName); // 儲存 BMP 檔案

下面是使用範例;

#define MAP(data, width, x, y) (data + ((y)*(width) + (x)))

#define getRGBbuf(width, height) ((sRGB *) malloc((width)*(height)*sizeof(sRGB)))

int main()

{

char *fname = "test.bmp";

int i,j;

if(LoadBMP(fname) == TRUE)

{

puts("讀檔成功!");

printf("width=%d, height=%dn", width, height);

img = getRGBbuf(width, height);

for(j=0;j<height;j++)

{

for(i=0;i<width;i++)

{

COLORREF c = getPixel(i, j);

MAP(img, width, i, j)->R = GetRValue(c);

MAP(img, width, i, j)->G = GetGValue(c);

MAP(img, width, i, j)->B = GetBValue(c);

}

}

FreeBMP();

// do process

SaveBMP(img, "out.bmp");

// Clear

free(img);

}

else

puts("讀檔失敗");

system("pause");

return 0;

}

讀取 BMP 檔案

// =================================

// 讀取 BMP 檔案

// =================================

HDC hMemDC;

BITMAP bm;

HBITMAP hBitmap, hOldBitmap;

HPALETTE hPalette;

BOOL LoadBMP(LPTSTR szFileName)

{

HPALETTE hOldPalette;

if( LoadBitmapFromBMPFile( szFileName, &hBitmap, &hPalette ) )

{

GetObject( hBitmap, sizeof(BITMAP), &bm );

hMemDC = CreateCompatibleDC( NULL );

hOldBitmap = (HBITMAP)SelectObject( hMemDC, hBitmap );

// 取得 寬&高

width = bm.bmWidth;

height = bm.bmHeight;

return TRUE;

}

return FALSE;

}

void FreeBMP()

{

DeleteObject( hBitmap );

DeleteObject( hPalette );

SelectObject( hMemDC, hOldBitmap );

DeleteDC( hMemDC );

}

COLORREF getPixel(int x, int y)

{

return GetPixel(hMemDC, x, y);

}

// Load BITMAP File using Win32 API

// From MSDN: http://support.microsoft.com/kb/158898/zh-tw

BOOL LoadBitmapFromBMPFile( LPTSTR szFileName, HBITMAP *phBitmap, HPALETTE *phPalette )

{

BITMAP bm;

*phBitmap = NULL;

*phPalette = NULL;

// Use LoadImage() to get the image loaded into a DIBSection

*phBitmap = (HBITMAP)LoadImage( NULL, szFileName, IMAGE_BITMAP, 0, 0,

LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE );

if( *phBitmap == NULL )

return FALSE;

// Get the color depth of the DIBSection

GetObject(*phBitmap, sizeof(BITMAP), &bm );

// If the DIBSection is 256 color or less, it has a color table

if( ( bm.bmBitsPixel * bm.bmPlanes ) <= 8 )

{

HDC hMemDC;

HBITMAP hOldBitmap;

RGBQUAD rgb[256];

LPLOGPALETTE pLogPal;

WORD i;

// Create a memory DC and select the DIBSection into it

hMemDC = CreateCompatibleDC( NULL );

hOldBitmap = (HBITMAP)SelectObject( hMemDC, *phBitmap );

// Get the DIBSection's color table

GetDIBColorTable( hMemDC, 0, 256, rgb );

// Create a palette from the color tabl

pLogPal = (LOGPALETTE *)malloc( sizeof(LOGPALETTE) + (256*sizeof(PALETTEENTRY)) );

pLogPal->palVersion = 0x300;

pLogPal->palNumEntries = 256;

for(i=0;i<256;i++)

{

pLogPal->palPalEntry[i].peRed = rgb[i].rgbRed;

pLogPal->palPalEntry[i].peGreen = rgb[i].rgbGreen;

pLogPal->palPalEntry[i].peBlue = rgb[i].rgbBlue;

pLogPal->palPalEntry[i].peFlags = 0;

}

*phPalette = CreatePalette( pLogPal );

// Clean up

free( pLogPal );

SelectObject( hMemDC, hOldBitmap );

DeleteDC( hMemDC );

}

else // It has no color table, so use a halftone palette

{

HDC hRefDC;

hRefDC = GetDC( NULL );

*phPalette = CreateHalftonePalette( hRefDC );

ReleaseDC( NULL, hRefDC );

}

return TRUE;

}

儲存 BMP 檔案

// =================================

// 儲存 BMP 檔案

// =================================

void SaveBMP(sRGB *data, LPCTSTR lpszFileName)

{

sRGB *buf = ReverseRGB_Row(data);

SaveBitmapToFile((BYTE*) buf, width, height, 24, lpszFileName);

free(buf);

}

// BMP 的 Row 好像是倒過來放的, 新的空間要加入 padding

sRGB *ReverseRGB_Row(sRGB *bmp)

{

unsigned char *buf;

int width2, j;

width2 = sizeof(sRGB) * width;

width2 = width2 + (4 - (width2 % 4));

buf = malloc(width2 * height);

memset(buf, 0, width2 * height);

for(j=0;j<height;j++)

{

memcpy(buf + j*width2, bmp + (height-1-j)*width, sizeof(sRGB)*width);

}

return buf;

}

// 儲存 Bitmap, From: http://www.wretch.cc/blog/slam963/26168717

void SaveBitmapToFile( BYTE* pBitmapBits, LONG lWidth, LONG lHeight, WORD wBitsPerPixel, LPCTSTR lpszFileName )

{

BITMAPFILEHEADER bfh = {0};

BITMAPINFOHEADER bmpInfoHeader = {0};

HANDLE hFile;

DWORD dwWritten;

LONG width2 = (wBitsPerPixel/8) * lWidth;

width2 = width2 + (4 - (width2 % 4));

bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER); // Set the size

bmpInfoHeader.biBitCount = wBitsPerPixel; // Bit count

bmpInfoHeader.biClrImportant = 0; // Use all colors

bmpInfoHeader.biClrUsed = 0; // Use as many colors according to bits per pixel

bmpInfoHeader.biCompression = BI_RGB; // Store as un Compressed

bmpInfoHeader.biHeight = lHeight; // Set the height in pixels

bmpInfoHeader.biWidth = lWidth; // Width of the Image in pixels

bmpInfoHeader.biPlanes = 1; // Default number of planes

// Calculate the image size in bytes

bmpInfoHeader.biSizeImage = width2 * lHeight;

// This value should be values of BM letters i.e 0×4D42

// 0×4D = M 0×42 = B storing in reverse order to match with endian

bfh.bfType=0x4D42;

// Offset to the RGBQUAD

bfh.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);

// Total size of image including size of headers

bfh.bfSize = bfh.bfOffBits + bmpInfoHeader.biSizeImage;

// Create the file in disk to write

hFile = CreateFile( lpszFileName,GENERIC_WRITE, 0,NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);

if( !hFile ) // return if error opening file

{

return;

}

dwWritten = 0;

// Write the File header

WriteFile( hFile, &bfh, sizeof(bfh), &dwWritten , NULL );

// Write the bitmap info header

WriteFile( hFile, &bmpInfoHeader, sizeof(bmpInfoHeader), &dwWritten, NULL );

// Write the RGB Data

WriteFile( hFile, pBitmapBits, bmpInfoHeader.biSizeImage, &dwWritten, NULL );

// Close the file handle

CloseHandle( hFile );

}

原文:http://hialan.blogspot.com/2009/11/win32-api-bmp.html