C语言读写BMP文件

参考的是:用C语言进行BMP文件的读写,以及:BMP格式介绍


首先是头文件bmp.h:

#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


其次是各个函数的实现bmp.cpp,主要是clLoadImage(载入)和clSaveImage(保存)这两个函数:
#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);  
                    }  
                }  
            }  
        }  
    }  
  
    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;  
}

最后测试一下:

#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;  
}  
执行完毕无问题,对比一下两张图片,结果是相同的:



  • 5
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是读取和写入BMP文件C语言代码示例: #### 读取BMP文件 ```c #include <stdio.h> #include <stdlib.h> #pragma pack(push, 1) typedef struct BMPHeader { uint16_t file_type; // 文件类型,必须为'BM' uint32_t file_size; // 文件大小 uint16_t reserved1; // 保留 uint16_t reserved2; // 保留 uint32_t data_offset; // 数据偏移量 uint32_t header_size; // 头文件大小 int32_t width; // 图像宽度 int32_t height; // 图像高度 uint16_t planes; // 必须为1 uint16_t bits_per_pixel; // 每个像素的位数 uint32_t compression; // 压缩类型,0为不压缩 uint32_t data_size; // 数据大小 int32_t x_pixels_per_meter;// 水平分辨率 int32_t y_pixels_per_meter;// 垂直分辨率 uint32_t colors_used; // 使用的颜色数 uint32_t important_colors; // 重要颜色数 } BMPHeader; #pragma pack(pop) int main() { FILE *fp; BMPHeader header; unsigned char *data; uint32_t row_size, padding_size; int i, j; // 打开文件 fp = fopen("image.bmp", "rb"); if (fp == NULL) { printf("无法打开文件\n"); return 1; } // 读取文件头 fread(&header, sizeof(header), 1, fp); // 校验文件格式 if (header.file_type != 0x4D42) { printf("不是BMP文件\n"); fclose(fp); return 1; } // 分配内存 row_size = ((header.bits_per_pixel * header.width + 31) / 32) * 4; padding_size = row_size - header.width * header.bits_per_pixel / 8; data = (unsigned char*) malloc(row_size * header.height); // 读取像素数据 fseek(fp, header.data_offset, SEEK_SET); for (i = 0; i < header.height; i++) { fread(&data[i * row_size], header.bits_per_pixel / 8, header.width, fp); fseek(fp, padding_size, SEEK_CUR); } // 关闭文件 fclose(fp); // 处理像素数据 for (i = 0; i < header.height; i++) { for (j = 0; j < header.width; j++) { // 处理像素 // data[i * row_size + j * header.bits_per_pixel / 8] = ... } } // 释放内存 free(data); return 0; } ``` #### 写入BMP文件 ```c #include <stdio.h> #include <stdlib.h> #pragma pack(push, 1) typedef struct BMPHeader { uint16_t file_type; // 文件类型,必须为'BM' uint32_t file_size; // 文件大小 uint16_t reserved1; // 保留 uint16_t reserved2; // 保留 uint32_t data_offset; // 数据偏移量 uint32_t header_size; // 头文件大小 int32_t width; // 图像宽度 int32_t height; // 图像高度 uint16_t planes; // 必须为1 uint16_t bits_per_pixel; // 每个像素的位数 uint32_t compression; // 压缩类型,0为不压缩 uint32_t data_size; // 数据大小 int32_t x_pixels_per_meter;// 水平分辨率 int32_t y_pixels_per_meter;// 垂直分辨率 uint32_t colors_used; // 使用的颜色数 uint32_t important_colors; // 重要颜色数 } BMPHeader; #pragma pack(pop) int main() { FILE *fp; BMPHeader header; unsigned char *data; uint32_t row_size, padding_size; int i, j; // 分配内存 header.width = 640; header.height = 480; header.bits_per_pixel = 24; row_size = ((header.bits_per_pixel * header.width + 31) / 32) * 4; padding_size = row_size - header.width * header.bits_per_pixel / 8; header.data_size = row_size * header.height; header.data_offset = sizeof(header); header.file_size = header.data_offset + header.data_size; data = (unsigned char*) malloc(row_size * header.height); // 填充像素数据 for (i = 0; i < header.height; i++) { for (j = 0; j < header.width; j++) { // 填充像素 // data[i * row_size + j * header.bits_per_pixel / 8] = ... } } // 打开文件 fp = fopen("image.bmp", "wb"); if (fp == NULL) { printf("无法打开文件\n"); return 1; } // 写入文件头 header.file_type = 0x4D42; header.reserved1 = 0; header.reserved2 = 0; header.planes = 1; header.compression = 0; header.x_pixels_per_meter = 0; header.y_pixels_per_meter = 0; header.colors_used = 0; header.important_colors = 0; header.header_size = sizeof(header); fwrite(&header, sizeof(header), 1, fp); // 写入像素数据 for (i = 0; i < header.height; i++) { fwrite(&data[i * row_size], header.bits_per_pixel / 8, header.width, fp); fwrite(&padding_size, 1, padding_size, fp); } // 关闭文件 fclose(fp); // 释放内存 free(data); return 0; } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值