linu下C语言之BMP图片操作编程(上)

本文介绍了BMP文件格式的基础知识,并展示了如何将rgb888格式的图像转换为rgb565格式的过程。通过代码实现,实现了BMP头的封装和数据读取,最终将图像数据从rgb888转换为rgb565,展示图像处理技术的应用。

   BMP文件格式,也被称为位图图像文件与设备无关的位图文件格式(DIB)或者只是一个位图,是 一个光栅图形 图像文件格式使用 来存储位图,数字,图片,独立的显示设备。

   微软已经定义了一个特定的表示颜色的位图 不同的颜色深度,作为援助交换设备和之间的位图 应用程序与各种各样的内部表示。 他们称这些 与设备无关的位图或权利,叫做DIB文件格式 文件格式或BMP图像文件格式。 根据微软的支持:

   与设备无关的位图(DIB)是一种用于定义格式 与设备无关的位图在各种颜色的决议。 的主要目的 权利是允许从一个设备转移到另一个位图(因此, 与设备无关的名字)的一部分。 DIB外部格式,形成鲜明对比 设备相关的位图,在系统作为一个位图对象 应用程序创建的(……)。 元的DIB通常运输 (通常使用StretchDIBits()函数),BMP文件,剪贴板 (CF_DIB数据格式)。

BMP图片格式图:


接下来来看一个代码对BMP头的封装,然后将rgb888转化成rgb565的现象的例程:

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

#define  RGB(r,g,b)    		(((r>>3)<<11)|((g>>2)<<5)|(b>>3))

typedef  unsigned char  U8 ; 
typedef  unsigned short U16 ; 
typedef  unsigned int   U32 ; 

#pragma  pack(1)
struct bmp_header    //这个结构体就是对上面那个图做一个封装。
{
	//bmp header
	U8  Signatue[2] ;   // B  M
	U32 FileSize ;     //文件大小
	U16 Reserv1 ; 
	U16 Reserv2 ; 
	U32 FileOffset ;   //文件头偏移量
	
	//DIB header
	U32 DIBHeaderSize ; //DIB头大小
	U32 ImageWidth   ;  //文件宽度
	U32 ImageHight   ;  //文件高度
	U16 Planes       ; 
	U16 BPP          ;  //每个相素点的位数
	U32 Compression  ; 
	U32 ImageSize    ;  //图文件大小
	U32 XPPM ; 
	U32 YPPM ; 
	U32 CCT ; 
	U32 ICC ;          
};
#pragma  pack()

int main(int argc , char **argv)
{
	//判断参数,传进来的参数不等于两个,那么就报错      ./a.out   xxx
	if(argc != 2)
		return -1 ; 
										
	int fd ; 
	int dest_fd ; 
	//以只读的方式打开一个文件  这个文件是rgb888
	fd = open(argv[1] , O_RDONLY);
	if(-1 == fd)
	{
		perror("open bmp file fail");
		return -2 ; 
	}

	//打开一个rgb565.bmp的图片
	dest_fd = open("rgb565.bmp" , O_RDWR | O_CREAT|O_TRUNC , 0777);
	if(dest_fd < 0 )
	{
		perror("open rgb565 fail");
		return -3 ; 
	}

	
	//定义一个bmp的头
	struct bmp_header  header ; 

	int ret ; 
	
	//读出bmp文件头的数据
	ret = read(fd , &header , sizeof(struct bmp_header));
	
	//以下是bmp图的相关数据
	printf(" Signatue[0]      : %c  \n " , header.Signatue[0]  );
	printf(" Signatue[1]      : %c  \n " , header.Signatue[1]  );
	printf(" FileSize         : %d  \n " , header.FileSize     );
	printf(" Reserv1          : %d  \n " , header.Reserv1      );
	printf(" Reserv2          : %d  \n " , header.Reserv2      );
	printf(" FileOffset       : %d  \n " , header.FileOffset   );
	printf(" DIBHeaderSize    : %d  \n " , header.DIBHeaderSize);
	printf(" ImageWidth       : %d  \n " , header.ImageWidth   );
	printf(" ImageHight       : %d  \n " , header.ImageHight   );
	printf(" Planes           : %d  \n " , header.Planes       );
	printf(" BPP              : %d  \n " , header.BPP          );
	printf(" Compression      : %d  \n " , header.Compression  );
	printf(" ImageSize        : %d  \n " , header.ImageSize    );
	printf(" XPPM             : %d  \n " , header.XPPM         );
	printf(" YPPM             : %d  \n " , header.YPPM         );
	printf(" CCT              : %d  \n " , header.CCT          );
	printf(" ICC              : %d  \n " , header.ICC          );

	char buffer[header.ImageSize] ; 

	read(fd , buffer , header.ImageSize);

	close(fd);

	//改变地方
	header.BPP = 16 ; 
	header.FileSize = header.ImageWidth*header.ImageHight*2+54 ; 
	header.ImageSize = header.ImageWidth*header.ImageHight*2;

	write(dest_fd , &header , sizeof(struct bmp_header));

	int row , col ; 
	short data ; 
	char *p = NULL ; 

	for(row = 0 ; row < header.ImageHight ; row++)
	{
		for(col = 0 ; col < header.ImageWidth ; col++)
		{
			p =( buffer+(row*header.ImageWidth + col)*3);
			data = RGB((unsigned char)(*(p+2)) , (unsigned char)(*(p+1)) , 
			(unsigned char )(*(p)));
			write(dest_fd , &data , 2);
		}
	}

	close(dest_fd);

	return 0 ; 
}
接下来我们来对这幅图进行操作,看看打印出什么信息:这副图就是1.bmp----->格式rgb888生气



运行结果:获取到bmp图的包头,顺便将rgb888的bmp图转化为rgb565生气


生成rgb565的bmp图:是不是发现像素差了一点?大笑


后续还会有bmp图相关的操作,例如BMP图旋转(左右转),bmp图的灰度处理

,欢迎继续关注Bruce.yang的嵌入式之旅大笑

<think>好的,我现在需要帮助用户解决在Linux系统中使用C语言获取正在运行进程的问题。用户要求示例代码,所以我得先回忆相关的系统调用和函数。 首先,获取进程信息通常涉及读取/proc文件系统。在Linux中,每个进程在/proc下有一个以PID命名的目录,里面包含了该进程的信息。用户可能需要遍历这些目录来获取所有正在运行的进程。 然后,我想到使用opendir和readdir函数来遍历/proc目录。每个子目录如果名称是数字,就代表一个进程。需要过滤掉非数字的目录,比如self、thread-self等。 接下来,对于每个PID目录,可以读取其中的status文件来获取进程的详细信息,比如进程名、UID、状态等。这里需要打开文件并逐行读取,直到找到所需的字段。 另外,用户可能需要获取进程的PID和PPID(父进程ID)。在status文件中,PPID在Name和Pid之后,所以需要正确解析这些行。 关于权限的问题,普通用户可能只能查看自己拥有的进程信息,所以要注意处理权限不足的情况,比如使用access函数检查文件是否可读。 然后,组织代码结构。首先打开/proc目录,遍历每个条目,判断是否为有效PID。对于每个PID,读取status文件,提取信息,并输出。最后关闭目录。 测试部分,用户可能需要编译代码,使用gcc并链接必要的库。运行后应该能看到类似ps命令的输出,但可能更简单。 可能的问题点:处理/proc中的非进程目录,错误处理(比如进程在读取时结束),字符串处理确保缓冲区不溢出,以及跨平台问题(仅限于Linux)。 最后,示例代码需要包含必要的头文件,比如stdio.h、dirent.h、sys/types.h等,并使用正确的函数调用。同时,要确保代码的健壮性,比如检查文件打开是否成功,读取是否出错等。 现在将这些思路整理成代码,并添加注释说明每一步的作用,确保用户能够理解。同时,生成相关问题,帮助用户深入学习和解决可能的问题。</think>以下是在Linux系统中使用C语言获取正在运行进程的示例代码和实现步骤: ### 实现步骤 1. **访问/proc文件系统** Linux通过虚拟文件系统`/proc`提供进程信息,每个进程对应一个以PID命名的目录,例如`/proc/1234` 2. **目录遍历** 使用`opendir()`和`readdir()`函数遍历`/proc`目录,筛选出数字命名的目录(即有效PID) 3. **读取进程信息** 通过读取`/proc/[PID]/status`文件获取进程详细信息 ```c #include <stdio.h> #include <dirent.h> #include <sys/types.h> #include <string.h> #include <stdlib.h> // 判断是否为有效PID(纯数字) int is_pid(const char *name) { while (*name) { if (*name < '0' || *name > '9') return 0; name++; } return 1; } // 获取进程信息 void get_process_info(pid_t pid) { char path[256]; FILE *fp; char line[256]; // 构建status文件路径 snprintf(path, sizeof(path), "/proc/%d/status", pid); if ((fp = fopen(path, "r")) == NULL) { return; // 进程可能已终止 } // 读取进程信息 while (fgets(line, sizeof(line), fp)) { if (strncmp(line, "Name:", 5) == 0) { printf("PID: %d\n", pid); printf("%s", line); } else if (strncmp(line, "PPid:", 5) == 0) { printf("%s", line); break; } } fclose(fp); printf("--------------------\n"); } int main() { DIR *dir; struct dirent *entry; if ((dir = opendir("/proc")) == NULL) { perror("opendir failed"); return 1; } while ((entry = readdir(dir)) != NULL) { if (entry->d_type == DT_DIR && is_pid(entry->d_name)) { pid_t pid = atoi(entry->d_name); get_process_info(pid); } } closedir(dir); return 0; } ``` ### 代码说明 1. **目录遍历** 使用`readdir()`遍历`/proc`目录,通过`is_pid()`过滤出有效进程目录 2. **信息提取** 通过解析`status`文件获取: - 进程名称(Name字段) - 进程ID(PID) - 父进程ID(PPid字段) 3. **错误处理** 包含基本的错误处理机制,如目录打开失败和进程终止的情况 ### 编译运行 ```bash gcc -o process_list process_list.c ./process_list ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值