转自:C语言读写BMP文件_holybin的博客-优快云博客_bmp文件读写
#ifndef BMP_H
#define BMP_H
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
//unsigned short bfType;
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
} ClBitMapFileHeader;
typedef struct
{
unsigned long biSize;
long biWidth;
long biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
long biXPelsPerMeter;
long biYPelsPerMeter;
unsigned long biClrUsed;
unsigned long biClrImportant;
} ClBitMapInfoHeader;
typedef struct
{
unsigned char rgbBlue; //该颜色的蓝色分量
unsigned char rgbGreen; //该颜色的绿色分量
unsigned char rgbRed; //该颜色的红色分量
unsigned char rgbReserved; //保留值
} ClRgbQuad;
typedef struct
{
int width;
int height;
int channels;
unsigned char* imageData;
}ClImage;
ClImage* clLoadImage(const char* path);
bool clSaveImage(const char* path, ClImage* bmpImg);
#endif
#include "bmp.h"
ClImage* clLoadImage(const char* path)
{
ClImage* bmpImg;
FILE* pFile;
unsigned short fileType;
ClBitMapFileHeader bmpFileHeader;
ClBitMapInfoHeader bmpInfoHeader;
int channels = 1;
int width = 0;
int height = 0;
int step = 0;
int offset = 0;
unsigned char pixVal;
ClRgbQuad* quad;
int i, j, k;
bmpImg = (ClImage*)malloc(sizeof(ClImage));
pFile = fopen(path, "rb");
if (!pFile)
{
free(bmpImg);
return NULL;
}
fread(&fileType, sizeof(unsigned short), 1, pFile);
if (fileType == 0x4D42)
{
//printf("bmp file! \n");
fread(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);
/*printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");
printf("bmp文件头信息:\n");
printf("文件大小:%d \n", bmpFileHeader.bfSize);
printf("保留字:%d \n", bmpFileHeader.bfReserved1);
printf("保留字:%d \n", bmpFileHeader.bfReserved2);
printf("位图数据偏移字节数:%d \n", bmpFileHeader.bfOffBits);*/
fread(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);
/*printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");
printf("bmp文件信息头\n");
printf("结构体长度:%d \n", bmpInfoHeader.biSize);
printf("位图宽度:%d \n", bmpInfoHeader.biWidth);
printf("位图高度:%d \n", bmpInfoHeader.biHeight);
printf("位图平面数:%d \n", bmpInfoHeader.biPlanes);
printf("颜色位数:%d \n", bmpInfoHeader.biBitCount);
printf("压缩方式:%d \n", bmpInfoHeader.biCompression);
printf("实际位图数据占用的字节数:%d \n", bmpInfoHeader.biSizeImage);
printf("X方向分辨率:%d \n", bmpInfoHeader.biXPelsPerMeter);
printf("Y方向分辨率:%d \n", bmpInfoHeader.biYPelsPerMeter);
printf("使用的颜色数:%d \n", bmpInfoHeader.biClrUsed);
printf("重要颜色数:%d \n", bmpInfoHeader.biClrImportant);
printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");*/
if (bmpInfoHeader.biBitCount == 8)
{
//printf("该文件有调色板,即该位图为非真彩色\n\n");
channels = 1;
width = bmpInfoHeader.biWidth;
height = bmpInfoHeader.biHeight;
offset = (channels * width) % 4;
if (offset != 0)
{
offset = 4 - offset;
}
//bmpImg->mat = kzCreateMat(height, width, 1, 0);
bmpImg->width = width;
bmpImg->height = height;
bmpImg->channels = 1;
bmpImg->imageData = (unsigned char*)malloc(sizeof(unsigned char) * width * height);
step = channels * width;
quad = (ClRgbQuad*)malloc(sizeof(ClRgbQuad) * 256);
fread(quad, sizeof(ClRgbQuad), 256, pFile);
free(quad);
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++)
{
fread(&pixVal, sizeof(unsigned char), 1, pFile);
bmpImg->imageData[(height - 1 - i) * step + j] = pixVal;
}
if (offset != 0)
{
for (j = 0; j < offset; j++)
{
fread(&pixVal, sizeof(unsigned char), 1, pFile);
}
}
}
}
else if (bmpInfoHeader.biBitCount == 24)
{
//printf("该位图为位真彩色\n\n");
channels = 3;
width = bmpInfoHeader.biWidth;
height = bmpInfoHeader.biHeight;
bmpImg->width = width;
bmpImg->height = height;
bmpImg->channels = 3;
bmpImg->imageData = (unsigned char*)malloc(sizeof(unsigned char) * width * 3 * height);
step = channels * width;
offset = (channels * width) % 4;
if (offset != 0)
{
offset = 4 - offset;
}
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++)
{
for (k = 0; k < 3; k++)
{
fread(&pixVal, sizeof(unsigned char), 1, pFile);
bmpImg->imageData[(height - 1 - i) * step + j * 3 + k] = pixVal;
}
//kzSetMat(bmpImg->mat, height-1-i, j, kzScalar(pixVal[0], pixVal[1], pixVal[2]));
}
if (offset != 0)
{
for (j = 0; j < offset; j++)
{
fread(&pixVal, sizeof(unsigned char), 1, pFile);
}
}
}
}
else if (bmpInfoHeader.biBitCount == 32)
{
//printf("该位图为位真彩色\n\n");
channels = 4;
width = bmpInfoHeader.biWidth;
height = bmpInfoHeader.biHeight;
bmpImg->width = width;
bmpImg->height = height;
bmpImg->channels = 4;
bmpImg->imageData = (unsigned char*)malloc(sizeof(unsigned char) * width * 4 * height);
step = channels * width;
offset = (channels * width) % 4;
if (offset != 0)
{
offset = 4 - offset;
}
for (i = 0; i < height; i++)
{
for (j = 0; j < width; j++)
{
for (k = 0; k < 4; k++)
{
fread(&pixVal, sizeof(unsigned char), 1, pFile);
bmpImg->imageData[(height - 1 - i) * step + j * 4 + k] = pixVal;
}
//kzSetMat(bmpImg->mat, height-1-i, j, kzScalar(pixVal[0], pixVal[1], pixVal[2]));
}
if (offset != 0)
{
for (j = 0; j < offset; j++)
{
fread(&pixVal, sizeof(unsigned char), 1, pFile);
}
}
}
}
}
return bmpImg;
}
bool clSaveImage(const char* path, ClImage* bmpImg)
{
FILE* pFile;
unsigned short fileType;
ClBitMapFileHeader bmpFileHeader;
ClBitMapInfoHeader bmpInfoHeader;
int step;
int offset;
unsigned char pixVal = '\0';
int i, j;
ClRgbQuad* quad;
pFile = fopen(path, "wb");
if (!pFile)
{
return false;
}
fileType = 0x4D42;
fwrite(&fileType, sizeof(unsigned short), 1, pFile);
if (bmpImg->channels == 3)//24位,通道,彩图
{
step = bmpImg->channels * bmpImg->width;
offset = step % 4;
if (offset != 4)
{
step += 4 - offset;
}
bmpFileHeader.bfSize = bmpImg->height * step + 54;
bmpFileHeader.bfReserved1 = 0;
bmpFileHeader.bfReserved2 = 0;
bmpFileHeader.bfOffBits = 54;
fwrite(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);
bmpInfoHeader.biSize = 40;
bmpInfoHeader.biWidth = bmpImg->width;
bmpInfoHeader.biHeight = bmpImg->height;
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = 24;
bmpInfoHeader.biCompression = 0;
bmpInfoHeader.biSizeImage = bmpImg->height * step;
bmpInfoHeader.biXPelsPerMeter = 0;
bmpInfoHeader.biYPelsPerMeter = 0;
bmpInfoHeader.biClrUsed = 0;
bmpInfoHeader.biClrImportant = 0;
fwrite(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);
for (i = bmpImg->height - 1; i > -1; i--)
{
for (j = 0; j < bmpImg->width; j++)
{
pixVal = bmpImg->imageData[i * bmpImg->width * 3 + j * 3];
fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
pixVal = bmpImg->imageData[i * bmpImg->width * 3 + j * 3 + 1];
fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
pixVal = bmpImg->imageData[i * bmpImg->width * 3 + j * 3 + 2];
fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
}
if (offset != 0)
{
for (j = 0; j < 4 - offset; j++)
{
pixVal = 0;
fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
}
}
}
}
else if (bmpImg->channels == 1)//8位,单通道,灰度图
{
step = bmpImg->width;
offset = step % 4;
if (offset != 4)
{
step += 4 - offset;
}
bmpFileHeader.bfSize = 54 + 256 * 4 + bmpImg->width;
bmpFileHeader.bfReserved1 = 0;
bmpFileHeader.bfReserved2 = 0;
bmpFileHeader.bfOffBits = 54 + 256 * 4;
fwrite(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);
bmpInfoHeader.biSize = 40;
bmpInfoHeader.biWidth = bmpImg->width;
bmpInfoHeader.biHeight = bmpImg->height;
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = 8;
bmpInfoHeader.biCompression = 0;
bmpInfoHeader.biSizeImage = bmpImg->height * step;
bmpInfoHeader.biXPelsPerMeter = 0;
bmpInfoHeader.biYPelsPerMeter = 0;
bmpInfoHeader.biClrUsed = 256;
bmpInfoHeader.biClrImportant = 256;
fwrite(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);
quad = (ClRgbQuad*)malloc(sizeof(ClRgbQuad) * 256);
for (i = 0; i < 256; i++)
{
quad[i].rgbBlue = i;
quad[i].rgbGreen = i;
quad[i].rgbRed = i;
quad[i].rgbReserved = 0;
}
fwrite(quad, sizeof(ClRgbQuad), 256, pFile);
free(quad);
for (i = bmpImg->height - 1; i > -1; i--)
{
for (j = 0; j < bmpImg->width; j++)
{
pixVal = bmpImg->imageData[i * bmpImg->width + j];
fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
}
if (offset != 0)
{
for (j = 0; j < 4 - offset; j++)
{
pixVal = 0;
fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
}
}
}
}
fclose(pFile);
return true;
}
inline LONG BmpPitchCB(const BITMAPINFOHEADER* pFormat)
{
return ((pFormat->biWidth * (pFormat->biBitCount >> 3) + 3) >> 2) << 2;
}
inline HRESULT SaveBmp(
LPCTSTR pFileName,
const void* pBuf,
LONG lBuf_W,
LONG lBuf_H,
LONG lBuf_Bit,
BOOL bAlign)
{
if (pBuf == NULL)
{
return E_INVALIDARG;
}
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
memset(&bih, 0, sizeof(bih));
bih.biSize = sizeof(bih);
bih.biPlanes = 1;
bih.biBitCount = (WORD)lBuf_Bit;
bih.biWidth = lBuf_W;
bih.biHeight = lBuf_H;
bih.biSizeImage = BmpPitchCB(&bih) * abs(bih.biHeight);
memset(&bfh, 0, sizeof(bfh));
bfh.bfType = ((WORD)('M' << 8) | 'B');
bfh.bfOffBits = 54;
bfh.bfSize = 54 + bih.biSizeImage;
// Correct the param
//
if (bAlign == false)
{
if (bih.biSizeImage == (DWORD)bih.biWidth * bih.biBitCount * abs(bih.biHeight) / 8)
{
bAlign = true;
}
}
//
HANDLE hFile = NULL;
do
{
hFile = CreateFile(
pFileName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == NULL || hFile == INVALID_HANDLE_VALUE)
{
hFile = NULL;
break;
}
DWORD dwWrited = 0;
if (WriteFile(hFile, &bfh, sizeof(bfh), &dwWrited, NULL) == false)
{
break;
}
if (WriteFile(hFile, &bih, sizeof(bih), &dwWrited, NULL) == false)
{
break;
}
if (bAlign)
{
if (WriteFile(hFile, pBuf, bih.biSizeImage, &dwWrited, NULL) == false)
{
break;
}
}
else
{
// bitmap format pitch
// ...................................xxx for 32 bit aligned
//
const BYTE* pRow = static_cast<const BYTE*>(pBuf);
const LONG nRow = bih.biSizeImage / abs(bih.biHeight);
LONG n = 0;
for (n = abs(bih.biHeight); n > 1; n--)
{
if (!WriteFile(hFile, pRow, nRow, &dwWrited, NULL))
{
break;
}
pRow += bih.biWidth * bih.biBitCount / 8;
}
if (n != 1)
{
break;
}
if (!WriteFile(hFile, pRow, bih.biWidth * bih.biBitCount / 8, &dwWrited, NULL))
{
break;
}
LONG nPlus = nRow - bih.biWidth * bih.biBitCount / 8;
if (nPlus > 0)
{
if (!WriteFile(hFile, pRow, nPlus, &dwWrited, NULL))
{
break;
}
}
}
CloseHandle(hFile);
return S_OK;
} while (false);
if (hFile)
{
CloseHandle(hFile);
}
return E_FAIL;
}
测试:
#include "bmp.h"
const char* fileName1 = "D:\\opencv_pic\\Lena.bmp";
const char* fileName2 = "D:\\opencv_pic\\Lena - 副本.bmp";
int main(int argc, char* argv[])
{
ClImage* img = clLoadImage(fileName1);
bool flag = clSaveImage(fileName2, img);
if(flag)
{
printf("save ok...\n");
}
else
{
printf("save failure...\n");
}
return 0;
}
2024.5.20:更新读取RGBA和谐RGBA图片的函数