c语言 图片.bmp读写示例

news2025/1/11 18:37:38

1 图片.bmp数据结构

BMP(Bitmap)文件格式是一种简单的位图图像格式,其数据结构分为几个主要部分:文件头、信息头、调色板(可选)和像素数据。下面是各部分的详细说明。

  1. 文件头(File Header)
bfType (2 bytes): 文件类型,通常为'BM'0x42 0x4D)。
bfSize (4 bytes): 文件大小(以字节为单位)。
bfReserved1 (2 bytes): 保留字,通常为0bfReserved2 (2 bytes): 保留字,通常为0bfOffBits (4 bytes): 从文件头到像素数据的偏移量。
  1. 信息头(DIB Header)
biSize (4 bytes): 信息头的大小(通常为40)。
biWidth (4 bytes): 图像宽度(以像素为单位)。
biHeight (4 bytes): 图像高度(以像素为单位)。
biPlanes (2 bytes): 色平面数,通常为1biBitCount (2 bytes): 每个像素的位数(如24位、32位)。
biCompression (4 bytes): 压缩类型(0为不压缩)。
biSizeImage (4 bytes): 图像数据的大小(可以为0)。
biXPelsPerMeter (4 bytes): 水平分辨率(像素每米)。
biYPelsPerMeter (4 bytes): 垂直分辨率(像素每米)。
biClrUsed (4 bytes): 使用的颜色数(0表示使用所有颜色)。
biClrImportant (4 bytes): 重要的颜色数(0表示所有)。
  1. 调色板(Color Palette)
    对于某些格式(如1位或4位色),可能会包含调色板。调色板由颜色索引组成,使用RGB格式(每个颜色占用4个字节,包含蓝、绿、红、保留字节)。

  2. 像素数据(Pixel Data)
    像素数据从bfOffBits指定的位置开始。像素的排列顺序通常是自下而上,从左到右,具体存储格式取决于biBitCount:

24位BMP:每个像素使用3个字节,分别表示蓝色、绿色和红色(BGR格式)。
32位BMP:每个像素使用4个字节(蓝、绿、红、透明度)。

在C语言中,BMP文件格式有一个特定的数据结构。BMP文件分为文件头、信息头和像素数据。下面是BMP文件的基本数据结构:

BMP 文件数据结构

#include <stdint.h>

// BMP 文件头
typedef struct {
    uint16_t bfType;      // 文件类型,通常为 'BM'
    uint32_t bfSize;      // 文件大小
    uint16_t bfReserved1; // 保留字段
    uint16_t bfReserved2; // 保留字段
    uint32_t bfOffBits;   // 像素数据的偏移量
} BMPFileHeader;

// BMP 信息头

typedef struct {
    uint32_t biSize;          // 信息头大小
    int32_t biWidth;          // 图像宽度
    int32_t biHeight;         // 图像高度
    uint16_t biPlanes;        // 色平面数,通常为1
    uint16_t biBitCount;      // 每个像素的比特数(如24位)
    uint32_t biCompression;   // 压缩类型
    uint32_t biSizeImage;     // 图像大小
    int32_t biXPelsPerMeter;   // 水平分辨率
    int32_t biYPelsPerMeter;   // 垂直分辨率
    uint32_t biClrUsed;       // 使用的颜色数
    uint32_t biClrImportant;   // 重要的颜色数
} BMPInfoHeader;

// 像素数据

typedef struct {
    uint8_t blue;    // 蓝色分量
    uint8_t green;   // 绿色分量
    uint8_t red;     // 红色分量
} RGBPix

2 解析 BMP 文件步骤

打开 BMP 文件:

FILE *file = fopen("image.bmp", "rb");
if (!file) {
    perror("Unable to open file");
    return;
}

读取文件头:

BMPFileHeader fileHeader;
fread(&fileHeader, sizeof(BMPFileHeader), 1, file);

读取信息头:

BMPInfoHeader infoHeader;
fread(&infoHeader, sizeof(BMPInfoHeader), 1, file);

读取像素数据:
根据 infoHeader.biWidth 和 infoHeader.biHeight 读取像素数据。

int row_padded = (infoHeader.biWidth * 3 + 3) & (~3); // 行填充到4的倍数
RGBPixel *pixels = malloc(infoHeader.biWidth * infoHeader.biHeight * sizeof(RGBPixel));

for (int i = 0; i < infoHeader.biHeight; i++) {
    fread(pixels + (infoHeader.biHeight - i - 1) * infoHeader.biWidth, sizeof(RGBPixel), infoHeader.biWidth, file);
    fseek(file, row_padded - infoHeader.biWidth * 3, SEEK_CUR);
}

关闭文件:
fclose(file);
注意事项
BMP文件通常以蓝色、绿色、红色(BGR)顺序存储像素。
图片数据行通常是4字节对齐,可能需要填充字节。
确保检查文件类型以确认它是一个合法的BMP文件。

3 c语言 .bmp图像读写示例

#include <stdio.h>
#include <stdlib.h>

#define BUF_SIZE 720*1280*3
#define IMG_NAME "fengjing720.bmp"
#define IMG_NEW "x1.bmp"

#pragma pack(push, 1) // 让结构体按照1字节对齐,确保读写顺序正确
typedef struct {
    unsigned short bfType;      // 文件类型
    unsigned int bfSize;        // 文件大小
    unsigned short bfReserved1; // 保留字
    unsigned short bfReserved2; // 保留字
    unsigned int bfOffBits;     // 像素数据偏移
} BITMAPFILEHEADER;

typedef struct {
    unsigned int biSize;          // 信息头大小
    int biWidth;                  // 图像宽度
    int biHeight;                 // 图像高度
    unsigned short biPlanes;      // 平面数
    unsigned short biBitCount;    // 每个像素的位数
    unsigned int biCompression;    // 压缩类型
    unsigned int biSizeImage;      // 图像大小
    int biXPelsPerMeter;          // 水平分辨率
    int biYPelsPerMeter;          // 垂直分辨率
    unsigned int biClrUsed;       // 使用的颜色索引
    unsigned int biClrImportant;  // 重要的颜色索引
} BITMAPINFOHEADER;
#pragma pack(pop)

BITMAPFILEHEADER bfHeader;
BITMAPINFOHEADER biHeader;


void readBMP(const char *filename,unsigned char *data,int size) {
    FILE *file = fopen(filename, "rb");
    if (!file) {
        perror("Failed to open file");
        return;
    }

   // BITMAPFILEHEADER bfHeader;
   // BITMAPINFOHEADER biHeader;

    fread(&bfHeader, sizeof(bfHeader), 1, file);
    fread(&biHeader, sizeof(biHeader), 1, file);

    if (bfHeader.bfType != 0x4D42) {
        printf("Not a BMP file.\n");
        fclose(file);
        return;
    }

    printf("Width: %d, Height: %d Offset:%d\n", biHeader.biWidth, biHeader.biHeight,bfHeader.bfOffBits);
 
    // 移动到像素数据部分
    fseek(file, bfHeader.bfOffBits, SEEK_SET);

    // 计算像素数据大小
    //*size = biHeader.biWidth * biHeader.biHeight * 3; // 24位RGB
    //unsigned char *data = (unsigned char *)malloc(imageSize);
    if (!data) {
        printf("Memory allocation failed\n");
        fclose(file);
        return;
    }

    fread(data, 1,size, file);
    fclose(file);

    // 处理像素数据(例如,打印第一个像素的RGB值)
    printf("First pixel RGB: (%d, %d, %d)\n", data[0], data[1], data[2]);

    //free(data);
}

void writeBMP( const char *filename,unsigned char *data,int size)
{
    FILE *file = fopen(filename, "wb");

    if (!file) {
        perror("Unable to create file");
        return;
    }

    // 写入文件头和信息头
    fwrite(&bfHeader, sizeof(bfHeader), 1, file);
    fwrite(&biHeader, sizeof(biHeader), 1, file);

    // 写入像素数据
    fwrite(data, 1,size, file);
    fclose(file);
}

int main() {
    char img_buf[BUF_SIZE];
    
    readBMP(IMG_NAME,img_buf,BUF_SIZE);
    printf("Width: %d, Height: %d Offset:%d\n", biHeader.biWidth, biHeader.biHeight,bfHeader.bfOffBits);
    writeBMP(IMG_NEW,img_buf,BUF_SIZE);

    return 0;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2035562.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

zabbix看图表的时候标题是乱码

直接进入到&#xff1a;/usr/share/zabbix/assets/fonts 然后进入到windows下边fonts选择一个自己喜欢的字体&#xff0c;上传到/usr/share/zabbix/assets/fonts 然后把内容graphfont.ttff覆盖即可

《网络编程实战系列》(17)网络桥接模式

文章目录 **桥接模式的基本原理****桥接模式的应用场景****桥接模式的优缺点****桥接模式的实现****总结**桥接模式(Bridge Mode)是一种网络配置模式,用于将多个网络接口或网络段连接在一起,使其在逻辑上形成一个单一的网络。这种模式常用于在不同网络之间传递数据包,并使…

超详解Haproxy七层代理及配置

1.七层、四层负载及正、反向代理 1.1四层与七层负载均衡的区别 所谓的四到七层负载均衡&#xff0c;就是在对后台的服务器进行负载均衡时&#xff0c;依据四层的信息或七层的信息来决定怎么样转发流量四层的负载均衡&#xff0c;就是通过发布三层的IP地址(VIP)&#xff0c;然…

C语言—函数栈帧

函数&#xff0c;一般都有返回值&#xff0c;函数名&#xff0c;参数&#xff0c;再下来还有什么mian函数&#xff0c;函数写出来就是要被调用的&#xff0c;上面图片上的代码&#xff0c;main函数和myadd函数&#xff0c;都要在自己的栈结构什么形成自己的栈&#xff0c;可以帮…

如何获取VS Code扩展的版本更新信息

获取VS Code 扩展的版本更新的需求 因为企业内部有架设私有扩展管理器的要求&#xff0c;但是对于一些官方市场的插件&#xff0c;希望可以自动获取这些扩展的更新并上传至私有扩展管理器。于是就有了本篇介绍的需求&#xff1a; 通过API的方式获取VS Code 扩展的更新。 关于…

Spring Boot集成sentinel快速入门Demo

1.什么是sentinel&#xff1f; 随着微服务的流行&#xff0c;服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件&#xff0c;主要以流量为切入点&#xff0c;从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、…

python从入门到精通:判断语句

目录 前言 1、布尔类型和比较运算符 2、if语句的基本格式 3、if else语句 4、if elif else语句 5、判断语句的嵌套 6、实战演练 前言 逻辑判断是生活中常见的行为。同样&#xff0c;在程序中&#xff0c;进行逻辑判断也是最为基础的功能。 判断是程序最基础最核心的逻辑…

远程桌面工具企业版:Splashtop Enterprise

在当今全球化和数字化的商业环境中&#xff0c;远程工作和分布式团队合作成为了新常态。企业需要一种高效、安全的远程桌面解决方案&#xff0c;能够满足不断变化的业务需求&#xff0c;同时确保数据的安全性和员工的生产力。Splashtop Enterprise 是一款为企业量身定制的远程桌…

haproxy负载均衡之-调度算法详解

HAProxy的调度算法分为静态调度算法、动态调度算法和其他调度算法静态算法&#xff1a;按照事先定义好的规则轮询公平调度&#xff0c;不关⼼后端服务器的当前负载、链接数和响应速度等&#xff0c;且⽆法实时修改权重&#xff0c;只能靠重启HAProxy⽣效。动态算法&#xff1a;…

【NI-DAQmx入门】LabVIEW数据采集基础应用程序框架

对于可管理规模的 LabVIEW 程序&#xff0c;分析现有程序或设计新程序的方法通常是从整体到具体&#xff0c;即从高级到低级的分析和设计。从一开始就直接深入细节可能会效率较低。 在设计阶段&#xff0c;开发人员首先将程序垂直划分为几个层级。从最顶层开始&#xff0c;他们…

强化学习之Actor-Critic算法(基于值函数和策略的结合)——以CartPole环境为例

0.简介 DQN算法作为基于值函数的方法代表&#xff0c;基于值函数的方法只学习一个价值函数。REINFORCE算法作为基于策略的方法代表&#xff0c;基于策略的方法只学习一个策略函数。Actor-Critic算法则结合了两种学习方法&#xff0c;其本质是基于策略的方法&#xff0c;因为其目…

element时间段选择器或时间选择器 只设置默认起始时间或者结束时间,不显示问题

element时间段选择器或时间选择器 只设置默认起始时间或者结束时间&#xff0c;不显示问题 <div v-for"(item,index) in [a,b]":key"item"><el-date-pickerv-if"b"v-model"value1[item]"type"datetimerange"value-…

16s功能注释Bugbase的安装使用--本地版

文章目录 概述介绍下载安装程序下载并配置环境安装依赖R包并显示帮助运行示例数据Bug及解决方法-☆ 使用输入文件准备-☆下载Greengenes数据库在QIIME2中操作R语言操作 运行Bugbase 概述 Bugbase依赖于Greegenes1与R 但是R现已更新到4.4以上&#xff0c;安装R包时会不兼容且输…

【时时三省】(C语言基础)结构体初阶

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 结构体的声明 结构的基础知识: 结构是一些值的集合&#xff0c;这些值称为成员变量。结构的每个成员可以是不同类型的变量 数组: 是一组相同类型的元素的集合 结构体: 也是一些值得集合…

python-二进制?十进制?(赛氪OJ)

[题目描述] 给定两个十进制整数 : A&#xff0c;B。 你需要把它们的二进制形式以十进制的运算法则相加输出结果。 例如&#xff1a; A3 , B2的时候&#xff0c;A 的二进制表示是 : 11 , &#x1d435;B 的二进制表示是 10 &#xff0c;你需要输出答案为 : 21。 输入格式…

基于 Flutter 从零开发一款产品(一)—— 跨端开发技术介绍

前言 相信很多开发者在学习技术的过程中&#xff0c;常常会陷入一种误区当中&#xff0c;就是学了很多技术理论知识&#xff0c;但是仍做不出什么产品出来&#xff0c;往往学了很多干货&#xff0c;但是并无实际的用处。其实&#xff0c;不论是做什么&#xff0c;我们都需要从…

嵌入式linux系统镜像制作day1

点击上方"蓝字"关注我们 01、前言 嵌入式设备&#xff08;例如心电图检测仪&#xff0c;售票系统等&#xff09;。尽管&#xff0c;嵌入式设备像那些智能手机一样&#xff0c;绝大多数都使用同样的硬件和软件&#xff0c;包括系统芯片SoC、储存、连接和多媒体接口、…

Could not find artifact net.sf.json-lib:json-lib:jar

一开始我改了maven的setting&#xff0c;由官网变为阿里云仓库&#xff0c;最后还是不行 <dependency><groupId>net.sf.json-lib</groupId><artifactId>json-lib</artifactId><version>2.0</version><classifier>jdk15</cl…

freeRTOS任务通知(Task Notifications)

目录 前言 一、任务通知概述 1.优势及限制 2.通知状态和通知值 二、任务通知的使用 两类函数 1.xTaskNotifyGive/ulTaskNotifyTake 2.xTaskNotify/xTaskNotifyWait 三、传输计数值代码示例 四、传输任意值代码示例 前言 所谓"任务通知"&#xff0c;你可以反…

螺旋矩阵 | LeetCode-59 | LeetCode-54 | 分类讨论

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 &#x1f383;分类不好&#xff0c;这道题就做不出来&#xff01;&#x1f388; &#x1f4cc;LeetCode链接&#xff1a;59. 螺旋矩阵 II &#x1f4cc;LeetCode链接…