纯C语言实现解析单色位图文件获取颜色值

news2024/11/20 18:34:36

在绘制单色位图时,需要考虑字节对齐问题。字节对齐是指数据存储在内存中时按照多字节对齐的原则进行存放,以提高访问效率。

为了实现这个函数,可以按照以下步骤进行:

  1. 计算每行像素数据的实际占用字节数:每个像素占用1个BIT位,即1/8个字节。 

  2. 计算每行像素数据的补齐字节数:为了满足字节对齐要求,需要计算每行像素数据需要补齐的字节数。 

  3. 计算每行像素数据所需的总字节数:包括实际占用字节数和补齐字节数。 总字节数 = 实际占用字节数 + 补齐字节数

  4. 遍历行数和列数,根据索引计算出当前像素在pData数组中的位置: 像素位置 = 行索引 * 总字节数

  5. 根据列索引计算当前像素所在的BIT位在一个BYTE中的偏移量: 偏移量 = 7 - (列索引 % 8)

  6. 根据位运算的方式,将当前像素的值写入pData中的相应位置: if(pData[像素位置]  & 偏移量);

注意一点:标准的单色位图文件遵循从下至上、从左至右的方式扫描并存储

完整利用纯C语言解析单色位图文件获取颜色值的代码实现如下:

typedef char			int8_t;
typedef unsigned char	uint8_t;
typedef unsigned short	uint16_t;
typedef unsigned int	uint32_t;
typedef int				int32_t;

#pragma pack(push, 1) // 字节对齐设置为1字节
typedef struct {
    uint16_t bfType;
    uint32_t bfSize;
    uint16_t bfReserved1;
    uint16_t bfReserved2;
    uint32_t bfOffBits;
} BMPFileHeader;

typedef struct {
    uint32_t biSize;
    int32_t biWidth;
    int32_t biHeight;
    uint16_t biPlanes;
    uint16_t biBitCount;
    uint32_t biCompression;
    uint32_t biSizeImage;
    int32_t biXPelsPerMeter;
    int32_t biYPelsPerMeter;
    uint32_t biClrUsed;
    uint32_t biClrImportant;
} BMPInfoHeader;

#pragma pack(pop)

// 提取单色位图的颜色
void DrawBitmap8(CDC *pDC, const uint32_t x, const uint32_t y, const uint32_t w, const uint32_t h, const uint8_t *pData) 
{
	uint32_t	index = 0, bitOffset = 0, pixelByte = 0, pixelValue = 0;
	uint32_t	bytesPerLine = 0;
	uint32_t	row = 0, col = 0, startX = 0, startY = 0;

	// 单色位图对齐计算方法
	bytesPerLine = (w + 7) / 8;
	bytesPerLine += (bytesPerLine % sizeof(size_t)) ? sizeof(size_t) - bytesPerLine % sizeof(size_t) : 0;

	for (row = 0; row < h; row++)		// 先按行扫描
	{
        for (col = 0; col < w; col++)	// 再按列扫描
		{
            // 获取当前像素在 pData 中的索引
			index = bytesPerLine * row + col / 8;

            // 获取当前像素在字节中的位偏移
            bitOffset = 7 - (col % 8);

            // 获取当前像素值(字节)
            pixelByte = pData[index];
            
            // 获取当前像素值的位状态
            pixelValue = (pixelByte >> bitOffset) & 1;
            
			startX = x + col;
			startY = y + h - 1 - row;	// 单色位图文件是从下向上再按行扫描

            // 绘制像素
			if(!pixelValue)	// 黑色
				pDC->SetPixel(startX, startY, RGB(0, 0, 0));
			else
				pDC->SetPixel(startX, startY, RGB(0, 255, 0));
        }
    }
}

// 纯C语言解析单色BMP文件并绘制在xy位置
int32_t loadBitmap8(const int8_t *pFile, CDC *pDC, const uint32_t x, const uint32_t y)
{
	BMPFileHeader	fileHeader; 
	BMPInfoHeader	infoHeader;
	uint32_t		bytesPerLine = 0;
	uint8_t			*pixelData = NULL;
	FILE			*file = NULL;

	file = fopen(pFile, "rb");
	if (file == NULL) {
		printf("无法打开位图文件\n");
		return -1; 
	}

	fread(&fileHeader, sizeof(BMPFileHeader), 1, file);
	fread(&infoHeader, sizeof(BMPInfoHeader), 1, file);
	
	// 检查位图文件是否是单色位图
	if (infoHeader.biBitCount != 1) {
		printf("不支持的位图类型\n");
		fclose(file);
		return -1; 
	}
	
	// 根据位图信息计算行字节数和补齐字节数
	bytesPerLine = (infoHeader.biWidth + 7) / 8;
	bytesPerLine += (bytesPerLine % sizeof(size_t)) ? sizeof(size_t) - bytesPerLine % sizeof(size_t) : 0;
	
	// 分配像素数据内存
	pixelData = (uint8_t *)malloc(bytesPerLine * infoHeader.biHeight);
	if (pixelData == NULL) {
		printf("内存分配失败\n");
		fclose(file);
		return -1; 
	}
	
	// 读取像素数据
	fseek(file, fileHeader.bfOffBits, SEEK_SET);
	fread(pixelData, bytesPerLine * infoHeader.biHeight, 1, file);
	fclose(file);
	
	// 从x,y点开始绘制w,h的单色位图
	DrawBitmap8(pDC, x, y, infoHeader.biWidth, infoHeader.biHeight, pixelData);
	
	// 绘制完毕释放内存
    free(pixelData);
	pixelData = NULL;

    return 0;
}

运行效果如下:

注意:CDC这个类为MFC专用的绘图函数,请自行实现SetPixel这个函数即可,如有需要完整工程在评论区留邮箱即可!

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

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

相关文章

Shellcode——绕过31

遇到了一道ctf题目&#xff0c;要求shellcode的每一个字节都必须大于31。 如果没有这个限制的话&#xff1a; 这是最方便的了。 但是必须大于31. 所以我想&#xff0c;那就吧所有小于31的加上31&#xff0c;然后运行的时候这部分代码自己修改自己。 也就是SMC,&#xff0…

(二开)Flink 修改源码拓展 SQL 语法

1、Flink 扩展 calcite 中的语法解析 1&#xff09;定义需要的 SqlNode 节点类-以 SqlShowCatalogs 为例 a&#xff09;类位置 flink/flink-table/flink-sql-parser/src/main/java/org/apache/flink/sql/parser/dql/SqlShowCatalogs.java 核心方法&#xff1a; Override pu…

redis缓存击穿 穿透

我们之前写了一把分布式锁 并且用redis写的, redis内部实现是比较完善的&#xff0c;但是我们公司用的时候 redis 至少都是主从&#xff0c;哨兵,cluster 很少有单机的 呢么我们分布式锁基于集群问题下会有什么问题 比如说当第一个线程设置一个key过来进行加锁&#xff0c;加锁…

html/css/javascript/js实现的简易打飞机游戏

源码下载地址 支持&#xff1a;远程部署/安装/调试、讲解、二次开发/修改/定制 视频浏览地址

Maven项目转为SpringBoot项目

Maven项目转为SpringBoot项目 前言创建一个maven项目前的软件的一些通用设置Maven仓库的设置其他的设置字符编码编译器注解支持 创建的Maven项目修改为Spring Boot项目修改pom.xml文件修改启动类-Main新建WAR包所需的类 添加核心配置文件 测试的控制器最后整个项目的目录结构![…

Bayes决策:身高与体重特征进行性别分类

代码与文件请从这里下载&#xff1a;Auorui/Pattern-recognition-programming: 模式识别编程 (github.com) 简述 分别依照身高、体重数据作为特征&#xff0c;在正态分布假设下利用最大似然法估计分布密度参数&#xff0c;建立最小错误率Bayes分类器&#xff0c;写出得到的决…

@AutoConfigurationPackage注解类

包名package org.springframework.boot.autoconfigure 方法 String[] basePackages() 向AutoConfigurationPackages中注册的基本包&#xff0c;使用basePackageClasses作为基于字符串的包的类型安全替代方案 Class<?>[] basePackageClasses() 键入basePackage…

VL10F后台生成发货单时报错:物料 XXXXX 状态被锁定/未激活(不允许发货)

错误原因&#xff1a;物料主数据&#xff1a;销售视图1中&#xff0c;物料的发货状态没有激活。MM02修改物料的发货状态后正常生成单据。

双十一值得买的数码产品、这几款都不容错过

一年一度的双11终于来了&#xff0c;相信很多朋友都打算在此次的双11入手自己想要的产品&#xff0c;作为一个数码爱好者&#xff0c;我也是在此次的双11入手了下面4款数码产品&#xff0c;一起来看看吧&#xff01; 1、不用入耳佩戴的开放式耳机 -官方售价&#xff1a;199 …

WebSocket协议:5分钟从入门到精通

一、内容概览 WebSocket的出现&#xff0c;使得浏览器具备了实时双向通信的能力。本文由浅入深&#xff0c;介绍了WebSocket如何建立连接、交换数据的细节&#xff0c;以及数据帧的格式。此外&#xff0c;还简要介绍了针对WebSocket的安全攻击&#xff0c;以及协议是如何抵御类…

互联网产品说明书指南,附撰写流程与方法

产品说明书&#xff0c;对于普通产品而言&#xff0c;再常见不过。药物、电器、电子产品等产品在正式出售时&#xff0c;往往都会附带一份产品说明书&#xff0c;以此告诉用户这个产品的功能与特性&#xff0c;并指导用户如何来使用这个产品。 产品说明书 那么&#xff0c;对于…

洗衣行业在线预约小程序+前后端完整搭建教程

大家好哇&#xff0c;好久不见&#xff01;今天源码师父来给大家推荐一款洗衣行业在线预约的小程序&#xff0c;带有前后端的完整搭建教程。 目前&#xff0c;人们对生活品质的追求不断提高&#xff0c;但生活节奏却也不断加快。对品质的追求遇到了忙碌的生活节奏&#xff0c;…

天锐绿盾终端安全管理系统

所谓透明&#xff0c;是指对使用者来说是未知的。当使用者在打开或编辑指定文件时&#xff0c;系统将自动对未加密的文件进行加密&#xff0c;对已加密的文件自动解密。文件在硬盘上是密文&#xff0c;在内存中是明文。一旦离开使用环境&#xff0c;由于应用程序无法得到自动解…

web安全-原发抗抵赖

原发抗抵赖 原发抗抵赖也称不可否认性&#xff0c;主要表现以下两种形式&#xff1a; 数据发送者无法否认其发送数据的事实。例如&#xff0c;A向B发信&#xff0c;事后&#xff0c;A不能否认该信是其发送的。数据接收者事后无法否认其收到过这些数据。例如&#xff0c;A向B发…

动态规划(记忆化搜索)

AcWing 901. 滑雪 给定一个 R行 C 列的矩阵&#xff0c;表示一个矩形网格滑雪场。 矩阵中第 i 行第 j 列的点表示滑雪场的第 i 行第 j 列区域的高度。 一个人从滑雪场中的某个区域内出发&#xff0c;每次可以向上下左右任意一个方向滑动一个单位距离。 当然&#xff0c;一个人能…

git更新代码时显示“auto-detection of host provider took too long“移除方法

git更新代码时显示"auto-detection of host provider took too long"移除方法 问题描述 在windows操作系统&#xff0c;未连接互连网电脑&#xff0c;更新内网代码库时显示“auto-detection of host provider took too long (>2000ms)”&#xff0c;如下图所示。…

idea 中配置 maven

前文叙述&#xff1a; 配置 maven 一共要设置两个地方&#xff1a;1、为当前项目设置2、为新项目设置maven 的下载和安装可参考我之前写过的文章&#xff0c;具体的配置文章中也都有讲解。1、为当前项目进行 maven 配置 配置 VM Options: -DarchetypeCataloginternal2、为新项…

设将n(n>1)个整数存放在一维数组R中。设计一个在时间和空间两方面都尽可能高效的算法。将R中保存的序列循环左移P(0<P<n)个位置

设将n&#xff08;n>1&#xff09;个整数存放在一维数组R中。设计一个在时间和空间两方面都尽可能高效的算法。将R中保存的序列循环左移P&#xff08;0<P<n&#xff09;个位置。即将R中保存的数据由&#xff08;x0,x1…,xn-1&#xff09;变为&#xff08;xp,xp1…x0,x…

vscode下ssh免密登录linux服务器

vscode使用ssh免密登录linux 1、安装SSH插件2、生成密钥3、linux安装ssh服务4、linux下配置公钥5、vscode远程登录 注&#xff1a;测试环境为window10Ubuntu1804/Ubuntu2204 1、安装SSH插件 扩展->搜索SSH->点击install进行安装&#xff0c;如下图所示&#xff1a; 2、…

【Linux】安装部署Redis

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ Redis安装部署linux 1.gcc编译环境2.c库环境3.…