C语言bmp图片读写,画点,画线

bmp文件信息头、文件头结构体:

#pragma pack(1)

typedef struct {
    uint16_t bfType;//位图类别,根据不同的操作系统而不同,在Windows中,此字段的值总为'BM'
    uint32_t bfSize;//BMP图像文件的大小
    uint16_t bfReserved1;//总为0
    uint16_t bfReserved2;//总为0
    uint32_t bfOffBits;//BMP图像数据的地址  54
    uint32_t biSize;//本结构的大小,根据不同的操作系统而不同,在Windows中,此字段的值总为28h字节=40字节
    uint32_t biWidth;// BMP图像的宽度,单位像素
    uint32_t biHeight;//总为0
    uint16_t biPlanes;//总为0
    uint16_t biBitCount;//BMP图像的色深,即一个像素用多少位表示,常见有1、4、8、16、24和32,分别对应单色、16色、256色、16位高彩色、24位真彩色和32位增强型真彩色
    uint32_t biCompression;//压缩方式,0表示不压缩,1表示RLE8压缩,2表示RLE4压缩,3表示每个像素值由指定的掩码决定
    uint32_t biSizeImage;// BMP图像数据大小,必须是4的倍数,图像数据大小不是4的倍数时用0填充补足
    uint32_t biXPelsPerMeter;//水平分辨率,单位像素/m
    uint32_t biYPelsPerMeter;//垂直分辨率,单位像素/m
    uint32_t biClrUsed;//BMP图像使用的颜色,0表示使用全部颜色,对于256色位图来说,此值为100h=256
    uint32_t biClrImportant;//重要的颜色数,此值为0时所有颜色都重要,对于使用调色板的BMP图像来说,当显卡不能够显示所有颜色时,此值将辅助驱动程序显示颜色
} BMPFILEHEADER, *bmpFileHead;

#pragma pack()

注意上面要使用内存对齐#pragma pack(1)    #pragma pack()

代码封装了五个接口函数:

int  bmp_load(BMP *pb, char *file);//读取图片
int  bmp_save(BMP *pb, char *file);//存储图片
void bmp_free(BMP *pb);//清除内存
void bmp_setpixel(BMP *pb, int x, int y, int r, int g, int b);//画点
void bmp_getpixel(BMP *pb, int x, int y, int *r, int *g, int *b);//获取点的rgb值

具体代码如下:

bmp.h

#ifndef __BMPFILE_H__
#define __BMPFILE_H__

typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned char uint8_t;
#define TRUE 1

typedef struct{
    uint8_t *pData; // 图像数据
    int nImgW; // 图像宽度
    int nImgH; // 图像高度
    int nBits; // 1,4,8,24,32
    char bInit; // 是否已进行初始化,TRUE:已初始化。不能直接用指针来判断pData是否已初始化,因为pData的初始值不为NULL
// 也不能用(!bInit)来判断是否初始化,必须用(TRUE!=bInit)
} BMP;

int  bmp_load(BMP *pb, char *file);
int  bmp_save(BMP *pb, char *file);
void bmp_free(BMP *pb);
void bmp_setpixel(BMP *pb, int x, int y, int r, int g, int b);
void bmp_getpixel(BMP *pb, int x, int y, int *r, int *g, int *b);

#endif

bmp.c

#include 
#include 
#include 
#include "bmpfile.h"

#define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4);

#pragma pack(1)
typedef struct {
    uint16_t bfType;//位图类别,根据不同的操作系统而不同,在Windows中,此字段的值总为'BM'
    uint32_t bfSize;//BMP图像文件的大小
    uint16_t bfReserved1;//总为0
    uint16_t bfReserved2;//总为0
    uint32_t bfOffBits;//BMP图像数据的地址  54
    uint32_t biSize;//本结构的大小,根据不同的操作系统而不同,在Windows中,此字段的值总为28h字节=40字节
    uint32_t biWidth;// BMP图像的宽度,单位像素
    uint32_t biHeight;//总为0
    uint16_t biPlanes;//总为0
    uint16_t biBitCount;//BMP图像的色深,即一个像素用多少位表示,常见有1、4、8、16、24和32,分别对应单色、16色、256色、16位高彩色、24位真彩色和32位增强型真彩色
    uint32_t biCompression;//压缩方式,0表示不压缩,1表示RLE8压缩,2表示RLE4压缩,3表示每个像素值由指定的掩码决定
    uint32_t biSizeImage;// BMP图像数据大小,必须是4的倍数,图像数据大小不是4的倍数时用0填充补足
    uint32_t biXPelsPerMeter;//水平分辨率,单位像素/m
    uint32_t biYPelsPerMeter;//垂直分辨率,单位像素/m
    uint32_t biClrUsed;//BMP图像使用的颜色,0表示使用全部颜色,对于256色位图来说,此值为100h=256
    uint32_t biClrImportant;//重要的颜色数,此值为0时所有颜色都重要,对于使用调色板的BMP图像来说,当显卡不能够显示所有颜色时,此值将辅助驱动程序显示颜色
} BMPFILEHEADER, *bmpFileHead;

typedef struct tagRGBQUAD {
    uint8_t rgbBlue;
    uint8_t rgbGreen;
    uint8_t rgbRed;
    uint8_t rgbReserved;
} RGBQUAD, *PRGB;

#pragma pack()

int bmp_load(BMP *pb, char *file){
    BMPFILEHEADER bmp; //BMP文件头 信息头结构体

    FILE* fp; //指向文件的指针
    RGBQUAD *ipRGB = NULL;
    uint32_t LineBytes; // 每行的字节数
    uint32_t ImgBytesSize; // 图像总字节数
    uint32_t NumColors;
    int i;

    // 先释放图像空间
    if (pb->bInit == TRUE) {
        free(pb->pData);
    }
    pb->pData = NULL;

    // 打开文件
    fp = fopen(file, "rb");
    if (fp == NULL) {
        printf("fopen error\n");
        return -1;
    }

    //读取信息头、文件头
    //把指针fp所指向的文件的头信息写入bf(地址)
    if (fread(&bmp, sizeof(BMPFILEHEADER), 1, fp) == 0)
            {
        printf("fread error\n");
    }

    printf("bf.bfSize = %d\n", bmp.bfSize);
    printf("bi.biSize = %d\n", bmp.biSize);
    printf("bi.biWidth = %d\n", bmp.biWidth);
    printf("bi.biHeight = %d\n", bmp.biHeight);
    printf("bi.biBitCount = %d\n", bmp.biBitCount);
    printf("bi.bfOffBits = %d\n", bmp.bfOffBits);
// 计算行字节数和总字节数
    LineBytes = (uint32_t) WIDTHBYTES(bmp.biWidth * bmp.biBitCount)
    ; //计算位图的实际宽度并确保它为32的倍数
    ImgBytesSize = (uint32_t) LineBytes * bmp.biHeight;

    if (bmp.biClrUsed != 0) {
        NumColors = (uint32_t) bmp.biClrUsed;
    } else {
        switch (bmp.biBitCount) {
        case 1:
            NumColors = 2;
            break;
        case 4:
            NumColors = 16;
            break;
        case 8:
            NumColors = 256;
            break;
        case 24:
            NumColors = 0;
            break;
        case 32:
            NumColors = 0;
            break;
        }
    }

    //分配调色板内存
    if ((bmp.biBitCount != 24) && (bmp.biBitCount != 32)) {
        ipRGB = (RGBQUAD *) malloc(NumColors * sizeof(RGBQUAD));
        fread(ipRGB, sizeof(RGBQUAD), NumColors, fp);
    }

    // 初始化图像bi
    printf("ImgBytesSize = %d\n", ImgBytesSize); //2430000
    pb->pData = (uint8_t*) malloc(sizeof(uint8_t) * ImgBytesSize); // 分配图像内存, 外部释放
    if (pb->pData == NULL) {
        free(ipRGB);
        return -1;
    }
    pb->nBits = bmp.biBitCount;
    pb->nImgW = bmp.biWidth;
    pb->nImgH = bmp.biHeight;
    pb->bInit = TRUE;

    if ((bmp.biBitCount == 32) || (bmp.biBitCount == 24)) {
        //fseek(fp, 4, SEEK_CUR); //SEEK_CUR:表示文件的相对当前位置
        for (i = pb->nImgH - 1; i >= 0; --i) {
            fread(pb->pData + i * LineBytes, 1, LineBytes, fp);
        }
    } else {
        for (i = pb->nImgH - 1; i >= 0; --i) {
            fread(pb->pData + i * LineBytes, 1, LineBytes, fp);
        }
    }
    fclose(fp);
    fp = NULL;

    free(ipRGB);

    return 0;
}

int bmp_save(BMP *pb, char *file) {
    BMPFILEHEADER bmp; //BMP文件头  信息头结构体
    RGBQUAD *ipRGB = NULL;
    uint32_t NumColors;
    int i;
    uint32_t nLineBytes = (uint32_t) WIDTHBYTES(pb->nImgW * pb->nBits);

    FILE* fp = NULL;

    if ((!file) || (TRUE != pb->bInit)) {
        return -1;
    }

    // 写入另一个文件
    fp = fopen(file, "wb");

    memset(&bmp, 0, sizeof(bmp));
    *((char*) &(bmp.bfType)) = 'B';
    *(((char*) &(bmp.bfType)) + 1) = 'M';
    bmp.bfReserved1 = 0;
    bmp.bfReserved2 = 0;
    bmp.bfOffBits = sizeof(BMPFILEHEADER);
    bmp.bfSize = pb->nImgW * pb->nImgH * (pb->nBits >> 3) + bmp.bfOffBits;

    bmp.biSize = 40;
    bmp.biBitCount = pb->nBits;
    printf("bi.biBitCount = %d\n", bmp.biBitCount);
    bmp.biWidth = pb->nImgW;
    bmp.biHeight = pb->nImgH;
    bmp.biCompression = 0;
    bmp.biPlanes = 1;
    bmp.biClrUsed = 0;

    fwrite(&bmp, sizeof(BMPFILEHEADER), 1, fp);

    if (bmp.biClrUsed != 0) {
        NumColors = (uint32_t) bmp.biClrUsed;
    } else {
        switch (bmp.biBitCount) {
        case 1:
            NumColors = 2;
            break;
        case 4:
            NumColors = 16;
            break;
        case 8:
            NumColors = 256;
            break;
        case 24:
            NumColors = 0;
            break;
        case 32:
            NumColors = 0;
            break;
        }
    }

    //分配调色板内存
    if ((bmp.biBitCount != 24) && (bmp.biBitCount != 32)) {
        ipRGB = (RGBQUAD *) malloc(NumColors * sizeof(RGBQUAD));
        fread(ipRGB, sizeof(RGBQUAD), NumColors, fp);
    }

    if ((bmp.biBitCount != 24) && (bmp.biBitCount != 32)) {
        fwrite(ipRGB, sizeof(RGBQUAD), NumColors, fp);
        for (i = (bmp.biHeight) - 1; i >= 0; i--) {
            fwrite(pb->pData + nLineBytes * i, sizeof(uint8_t), nLineBytes, fp);
        }
    } else {
        for (i = (bmp.biHeight) - 1; i >= 0; i--) {
            fwrite(pb->pData + nLineBytes * i, sizeof(uint8_t), nLineBytes,fp);
        }
    }

    fclose(fp);
    fp = NULL;
    free(ipRGB);
    return 0;
}

void bmp_free(BMP *pb){
    if (pb != NULL) {
        free(pb);
        pb = NULL;
    }
}

void bmp_setpixel(BMP *pb, int x, int y, int r, int g, int b) {
    pb->pData[y * pb->nImgW * 3 + x * 3 + 0] = b;
    pb->pData[y * pb->nImgW * 3 + x * 3 + 1] = g;
    pb->pData[y * pb->nImgW * 3 + x * 3 + 2] = r;
}

void bmp_getpixel(BMP *pb, int x, int y, int *r, int *g, int *b) {
    *b = pb->pData[y * pb->nImgW * 3 + x * 3 + 0];
    *g = pb->pData[y * pb->nImgW * 3 + x * 3 + 1];
    *r = pb->pData[y * pb->nImgW * 3 + x * 3 + 2];
}

int main(void) {
    char filename1[] = "./1.bmp";
    char filename2[] = "./2.bmp";

    BMP* pmi = (BMP *) malloc(sizeof(BMP));
    if(pmi == NULL){
        printf("malloc error\n");
    }

    if ((bmp_load((BMP *)&pmi,filename1)) < 0) {
        printf("bmp_load error\n");
    }

    //测试画点
      for (int y = 50; y < 60; y++) {
          for (int x = 50; x < 100; x++) {
              bmp_setpixel((BMP *)&pmi, x, y, 0, 0, 255);
          }
      }
    if ((bmp_save((BMP *)&pmi,filename2)) < 0) {
        printf("bmp_save error\n");
    }

    bmp_free(pmi);

    return EXIT_SUCCESS;
}

上面的代码是笔者实现的,不足是肯定有的,下面的代码是老师给的参考代码,可以实现上面的功能,还可以画框。

 bmpfile.c:

#include 
#include 
#include 
#include "bmpfile.h"

#define ALIGN(a, b) (((a) + (b) - 1) & ~((b) - 1))
#define MAX(a, b)   ((a) > (b) ? (a) : (b))
#define MIN(a, b)   ((a) < (b) ? (a) : (b))
#define _TEST2_ 1
//++ for bmp file ++//
// 内部类型定义
#pragma pack(1)

//typedef struct {
//	uint16_t  bfType;
//	uint32_t  bfSize;
//	uint16_t  bfReserved1;
//	uint16_t  bfReserved2;
//	uint32_t  bfOffBits;
//	uint32_t  biSize;
//	uint32_t  biWidth;
//	uint32_t  biHeight;
//	uint16_t  biPlanes;
//	uint16_t  biBitCount;
//	uint32_t  biCompression;
//	uint32_t  biSizeImage;
//	uint32_t  biXPelsPerMeter;
//	uint32_t  biYPelsPerMeter;
//	uint32_t  biClrUsed;
//	uint32_t  biClrImportant;
//} BMPFILEHEADER;
	
typedef struct {
	uint16_t bfType;//位图类别,根据不同的操作系统而不同,在Windows中,此字段的值总为'BM'
	uint32_t bfSize;//BMP图像文件的大小
	uint16_t bfReserved1;//总为0
	uint16_t bfReserved2;//总为0
	uint32_t bfOffBits;//BMP图像数据的地址  54
	uint32_t biSize;//本结构的大小,根据不同的操作系统而不同,在Windows中,此字段的值总为28h字节=40字节
	uint32_t biWidth;// BMP图像的宽度,单位像素
	uint32_t biHeight;//总为0
	uint16_t biPlanes;//总为0
	uint16_t biBitCount;//BMP图像的色深,即一个像素用多少位表示,常见有1、4、8、16、24和32,分别对应单色、16色、256色、16位高彩色、24位真彩色和32位增强型真彩色
	uint32_t biCompression;//压缩方式,0表示不压缩,1表示RLE8压缩,2表示RLE4压缩,3表示每个像素值由指定的掩码决定
	uint32_t biSizeImage;// BMP图像数据大小,必须是4的倍数,图像数据大小不是4的倍数时用0填充补足
	uint32_t biXPelsPerMeter;//水平分辨率,单位像素/m
	uint32_t biYPelsPerMeter;//垂直分辨率,单位像素/m
	uint32_t biClrUsed;//BMP图像使用的颜色,0表示使用全部颜色,对于256色位图来说,此值为100h=256
	uint32_t biClrImportant;//重要的颜色数,此值为0时所有颜色都重要,对于使用调色板的BMP图像来说,当显卡不能够显示所有颜色时,此值将辅助驱动程序显示颜色
} BMPFILEHEADER, *bmpFileHead;
#pragma pack()

/* 函数实现 */
int bmp_load(BMP *pb, char *file)
{
    BMPFILEHEADER header = {0};
    FILE         *fp     = NULL;
    uint8_t      *pdata  = NULL;
    int           i;

    fp = fopen(file, "rb");
    if (!fp) return -1;

    fread(&header, sizeof(header), 1, fp);
    pb->width  = header.biWidth;
    pb->height = header.biHeight;
    pb->stride = ALIGN(header.biWidth * 3, 4);//琛屽瓧鑺傛暟pb->stride 
    //鍦?4浣峛mp鍥句腑锛屼竴涓儚绱犳槸涓€涓偣锛岃€屼竴涓儚绱犳湁24浣嶏紝鍗?涓瓧鑺傘€?
    pb->cdepth = 24;
    pb->pdata  = malloc(pb->stride * pb->height);
    if (pb->pdata) {
        pdata  = (uint8_t*)pb->pdata + pb->stride * pb->height;//鎸囧悜鏈€鍚庝竴琛?
        for (i=0; iheight; i++) {
            pdata -= pb->stride;//鍚戜笂
            fread(pdata, pb->stride, 1, fp);//鎸夎璇诲彇
        }
    }

    fclose(fp);
    return pb->pdata ? 0 : -1;
}

int bmp_create(BMP *pb)
{
    pb->stride = ALIGN(pb->width * (pb->cdepth / 8), 4);
	//鍍忕礌閫氬父鐢ㄦ潵琛ㄧず浣嶅浘涓殑涓€涓偣銆備竴涓瓧鑺傚寘鍚?涓瘮鐗癸紝
	//鍦ㄥ鏉備竴浜涚殑浣嶅浘锛堜緥濡?4浣嶇湡褰╄壊BMP锛夛紝涓€涓儚绱犵敱涓変釜瀛楄妭鏋勬垚锛屾瘡涓瓧鑺傚垎鍒〃绀?56绉嶇姸鎬佺殑绾€佺豢銆佽摑銆傝繖鏍峰彲浠ヨ〃鐜扮浉褰撲赴瀵岀殑鑹插僵銆?
    pb->pdata  = calloc(1, pb->width * pb->stride);
    return pb->pdata ? 0 : -1;
}

int bmp_save(BMP *pb, char *file)
{
    BMPFILEHEADER header = {0};
    FILE         *fp     = NULL;
    uint8_t      *pdata;
    int           i;

    header.bfType     = ('B' << 0) | ('M' << 8);
    header.bfSize     = sizeof(header) + pb->stride * pb->height;
    header.bfOffBits  = sizeof(header);
    header.biSize     = 40;
    header.biWidth    = pb->width;
    header.biHeight   = pb->height;
    header.biPlanes   = 1;
    header.biBitCount = pb->cdepth;
    header.biSizeImage= pb->stride * pb->height;

    fp = fopen(file, "wb");
    if (fp) {
        fwrite(&header, sizeof(header), 1, fp);
        pdata = (uint8_t*)pb->pdata + pb->stride * pb->height;
        for (i=0; iheight; i++) {
            pdata -= pb->stride;
            fwrite(pdata, pb->stride, 1, fp);//鎸夎鍐欏叆
        }
        fclose(fp);
    }

    return fp ? 0 : -1;
}

void bmp_free(BMP *pb)
{
    if (pb->pdata) {
        free(pb->pdata);
        pb->pdata = NULL;
    }
    pb->width  = 0;
    pb->height = 0;
    pb->stride = 0;
    pb->cdepth = 0;
}

void bmp_setpixel(BMP *pb, int x, int y, int r, int g, int b)//x,y琛ㄧず鍦ㄥ摢涓儚绱犵偣
{
    uint8_t *pbyte = pb->pdata;
    if (x < 0 || y < 0 || x >= pb->width || y >= pb->height) return;
//  r = r < 0 ? 0 : r < 255 ? r : 255;
//  g = g < 0 ? 0 : g < 255 ? g : 255;
//  b = b < 0 ? 0 : b < 255 ? b : 255;
    pbyte[x * (pb->cdepth / 8) + 0 + y * pb->stride] = b;//pb->cdepth鍍忕礌浣嶆暟 pb->cdepth = 24;x鏄儚绱犵偣鐨勬í鍧愭爣锛?4浣峛mp涓竴涓儚绱犵偣涓変釜瀛楄妭銆?
    pbyte[x * (pb->cdepth / 8) + 1 + y * pb->stride] = g;//pb->stride 琛屽瓧鑺傛暟 pb->stride = ALIGN(header.biWidth * 3, 4);
    pbyte[x * (pb->cdepth / 8) + 2 + y * pb->stride] = r;//header.biWidth BMP鍥惧儚鐨勫搴︼紝鍗曚綅鍍忕礌

void bmp_getpixel(BMP *pb, int x, int y, int *r, int *g, int *b)
{
    uint8_t *pbyte = pb->pdata;
    if (x < 0 || y < 0 || x >= pb->width || y >= pb->height) { *r = *g = *b = 0; return; }
    *b = pbyte[x * (pb->cdepth / 8) + 0 + y * pb->stride];
    *g = pbyte[x * (pb->cdepth / 8) + 1 + y * pb->stride];
    *r = pbyte[x * (pb->cdepth / 8) + 2 + y * pb->stride];
}

void bmp_dotmatrix(BMP *pb, int x, int y, int r, int g, int b, char *matrix, int mw, int mh)
{
    int  i;
    mw = ALIGN(mw, 8);
    for (i=0; i= 0xA1) {
                int qm = (uint8_t)text[0] - 0xA1, wm = (uint8_t)text[1] - 0xA1;
                fseek(fphz, (qm * 94 + wm) * szhz, SEEK_SET);
                fread(matbuf, 1, szhz, fphz);
                text++;
            } else goto next;
        }
        bmp_dotmatrix(pb, cx, cy + MAX(asch, hzh) - mh, r, g, b, matbuf, mw, mh);
next:   cx += dx, text++;
    }
    if (fpasc) fclose(fpasc);
    if (fphz ) fclose(fphz );
    free(matbuf);
}

void bmp_fillrect(BMP *pb, int x, int y, int w, int h, int r, int g, int b, int alpha)
{
    int fr = r, fg = g, fb = b, br, bg, bb, i, j;
    for (i=0; i

bmpfile.h:

#ifndef __BMPFILE_H__
#define __BMPFILE_H__

/* BMP 对象的类型定义 */
typedef struct {
    int   width;   /* 宽度 */
    int   height;  /* 高度 */
    int   stride;  /* 行字节数 */
    int   cdepth;  /* 像素位数 */
    void *pdata;   /* 指向数据 */
} BMP;

int  bmp_load(BMP *pb, char *file);
int  bmp_save(BMP *pb, char *file);
void bmp_free(BMP *pb);
void bmp_setpixel (BMP *pb, int x, int y, int  r, int  g, int  b);
void bmp_getpixel (BMP *pb, int x, int y, int *r, int *g, int *b);
void bmp_dotmatrix(BMP *pb, int x, int y, int r, int g, int b, char *matrix, int mw, int mh);
void bmp_drawtext (BMP *pb, int x, int y, int r, int g, int b, char *text, char *ascfont, int ascw, int asch, char *hzfont, int hzw, int hzh);
void bmp_fillrect (BMP *pb, int x, int y, int w, int h, int r, int g, int b, int alpha);
void bmp_bitblt   (BMP *pbdst, int dstx, int dsty, BMP *pbsrc, int srcx, int srcy, int w, int h);

#endif

你可能感兴趣的:(c语言,开发语言)