Linux开发_介绍BMP图片上下翻转、添加水印

举报
DS小龙哥 发表于 2022/05/17 23:00:15 2022/05/17
【摘要】 介绍BMP图片上下翻转、添加水印、通过学习BMP图片结构学习文件编程。

BMP图片练习文件操作(专题练习)

1.​ BMP图片数据取模,模拟图片取模软件。(选择16位或者24位取模方式)

16位。

2.​ BMP图片放大缩小,根据输入的尺寸放大缩小图片。

3.​ 实现图片4种翻转效果: 上、、左、右。

4.​ 给图片的指定位置添加水印

要求: 在图片的任意位置,添加任意的文字水印。

比如: xxx路口 20181008 11:04

将字库加入: ASCII和中文GBK字库

​ 目录作业: 拷贝目录下所有文件(指定后缀的文件)到指定目录下,考虑一层目录。

多层目录拷贝。

​ Makefile作业: 使用Makefile建立工程,只需要写一个Makefile文件。

(1)BMP图片上下翻转实现

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

/* 必须在结构体定义之前使用,这是为了让结构体中各成员按1字节对齐 */
#pragma pack(1)

/*需要文件信息头:14个字节 */
struct tagBITMAP_FILE_HEADER
{
	unsigned short bfType;   //保存图片类似。 'BM' -- 0x4d42
	unsigned int  bfSize;      //图片的大小
	unsigned short bfReserved1;
	unsigned short bfReserved2;
	unsigned int  bfOffBits;  //RGB数据偏移地址
};

/* 位图参数信息 */
struct tagBITMAP_INFO_HEADER { 
	unsigned long  biSize;      //结构体大小
	unsigned long  biWidth;		//宽度
	unsigned long  biHeight;	//高度
	unsigned short biPlanes;
	unsigned short biBitCount;	//颜色位数
	unsigned long  biCompression;
	unsigned long  biSizeImage;
	unsigned long  biXPelsPerMeter;
	unsigned long  biYPelsPerMeter;
	unsigned long  biClrUsed;
	unsigned long  biClrImportant;
};

/*
函数功能: BMP图片翻转
函数参数:
		char *src_BmpFile     :BMP图片源文件
		char *new_BmpFile     :新文件
返回值  :0表示成功,其他值失败
*/
int BMPOverturn(char *src_BmpFile,char *new_BmpFile)
{
	/*1. 打开源文件*/
	int err=0;
	FILE *bmp_file=fopen(src_BmpFile,"rb");
	if(bmp_file==NULL)
	{
		err=1;
		goto ERROR;
	}
	
	/*2. 图片参数获取*/
	struct tagBITMAP_FILE_HEADER src_head; //BMP文件头
	memset(&src_head,0,sizeof(struct tagBITMAP_FILE_HEADER));
	if(fread(&src_head,1,sizeof(struct tagBITMAP_FILE_HEADER),bmp_file)!=sizeof(struct tagBITMAP_FILE_HEADER))
	{
		err=2;
		goto ERROR;
	}
	
	if(src_head.bfType!=0x4d42) //判断类型
	{
		err=3;
		goto ERROR;
	}
	
	struct tagBITMAP_INFO_HEADER src_info; //BMP图像参数
	memset(&src_info,0,sizeof(struct tagBITMAP_INFO_HEADER));
	if(fread(&src_info,1,sizeof(struct tagBITMAP_INFO_HEADER),bmp_file)!=sizeof(struct tagBITMAP_INFO_HEADER))
	{
		err=4;
		goto ERROR;
	}
	
	if(src_info.biBitCount!=24) //判断颜色位数
	{
		err=5;
		goto ERROR;
	}
	
	/*3. 创建新图片*/
	FILE *new_file=fopen(new_BmpFile,"wb");
	if(new_file==NULL)
	{
		err=6;
		goto ERROR;
	}
	
	/*3.1 创建BMP文件头*/
	fwrite(&src_head,1,sizeof(struct tagBITMAP_FILE_HEADER),new_file);
	
	/*3.2 创建BMP图像参数*/
	fwrite(&src_info,1,sizeof(struct tagBITMAP_INFO_HEADER),new_file);

	/*3.3 实现图片上下翻转*/
	int i;
	int lineByte=src_info.biWidth*3; //一行总字节数量
	if(lineByte%4)lineByte++;
	
	int offset=lineByte*(src_info.biHeight-1)+src_head.bfOffBits;
	char *data_p=malloc(lineByte);
	if(data_p==NULL)
	{
		err=7;
		goto ERROR;
	}
	
	for(i=0;i<src_info.biHeight;i++)
	{
		fseek(bmp_file,offset,SEEK_SET);
		fread(data_p,1,lineByte,bmp_file);
		fwrite(data_p,1,lineByte,new_file);
		offset-=lineByte;
	}
	
ERROR:	
	if(data_p)free(data_p);
	if(bmp_file)fclose(bmp_file);
	if(new_file)fclose(new_file);
	return err;
}

int main(int argc,char **argv)
{
	char cmd_buff[100];
	if(argc!=3)
	{
		printf("参数格式: ./app <源bmp图片名称> <新bmp图片名称>\n");
		return 0;
	}
	
	//上下翻转图片
	int err=BMPOverturn(argv[1],argv[2]);
	if(err)
	{
		printf("图片上下翻转失败!\n");
	}
	else
	{
		printf("图片上下翻转处理成功,新图片名称:%s\n",argv[2]);
		sprintf(cmd_buff,"eog %s",argv[2]);
		system(cmd_buff);
	}
	return 0;
}

(2)BMP图片水印添加

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

/* 必须在结构体定义之前使用,这是为了让结构体中各成员按1字节对齐 */
#pragma pack(1)

/*需要文件信息头:14个字节 */
struct tagBITMAP_FILE_HEADER
{
	unsigned short bfType;   //保存图片类似。 'BM' -- 0x4d42
	unsigned int  bfSize;      //图片的大小
	unsigned short bfReserved1;
	unsigned short bfReserved2;
	unsigned int  bfOffBits;  //RGB数据偏移地址
};

/* 位图参数信息 */
struct tagBITMAP_INFO_HEADER { 
	unsigned long  biSize;      //结构体大小
	unsigned long  biWidth;		//宽度
	unsigned long  biHeight;	//高度
	unsigned short biPlanes;
	unsigned short biBitCount;	//颜色位数
	unsigned long  biCompression;
	unsigned long  biSizeImage;
	unsigned long  biXPelsPerMeter;
	unsigned long  biYPelsPerMeter;
	unsigned long  biClrUsed;
	unsigned long  biClrImportant;
};

/*--  文字:  水  --*/
/*--  宋体42;  此字体下对应的点阵为:宽x高=56x56   --*/
const unsigned char font0[]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,
0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,
0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,
0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,
0x7C,0x00,0x0C,0x00,0x00,0x00,0x00,0x7C,0x00,0x0E,0x00,0x00,0x00,0x00,0x7E,0x00,
0x1F,0x00,0x00,0x00,0x00,0x7E,0x00,0x3F,0x80,0x00,0x00,0x00,0x7E,0x00,0x7F,0xC0,
0x00,0x00,0x18,0x7E,0x00,0xFE,0x00,0x00,0x00,0x3C,0x7F,0x00,0xF8,0x00,0x1F,0xFF,
0xFE,0x7F,0x03,0xF0,0x00,0x0F,0xFF,0xFF,0x7F,0x87,0xC0,0x00,0x07,0x80,0x7E,0x7F,
0x8F,0x80,0x00,0x00,0x00,0x7C,0x7F,0x9F,0x00,0x00,0x00,0x00,0x7C,0x7F,0xFC,0x00,
0x00,0x00,0x00,0xF8,0x7D,0xF8,0x00,0x00,0x00,0x00,0xF8,0x7D,0xE0,0x00,0x00,0x00,
0x00,0xF8,0x7C,0xE0,0x00,0x00,0x00,0x01,0xF0,0x7C,0xF0,0x00,0x00,0x00,0x01,0xF0,
0x7C,0xF0,0x00,0x00,0x00,0x01,0xF0,0x7C,0x78,0x00,0x00,0x00,0x03,0xE0,0x7C,0x7C,
0x00,0x00,0x00,0x03,0xE0,0x7C,0x3C,0x00,0x00,0x00,0x07,0xC0,0x7C,0x3E,0x00,0x00,
0x00,0x07,0xC0,0x7C,0x1E,0x00,0x00,0x00,0x0F,0x80,0x7C,0x1F,0x00,0x00,0x00,0x0F,
0x80,0x7C,0x0F,0x80,0x00,0x00,0x1F,0x00,0x7C,0x0F,0xC0,0x00,0x00,0x1E,0x00,0x7C,
0x07,0xE0,0x00,0x00,0x3E,0x00,0x7C,0x03,0xE0,0x00,0x00,0x3C,0x00,0x7C,0x03,0xF0,
0x00,0x00,0x78,0x00,0x7C,0x01,0xFC,0x00,0x00,0xF8,0x00,0x7C,0x00,0xFE,0x00,0x00,
0xF0,0x00,0x7C,0x00,0xFF,0x00,0x01,0xE0,0x00,0x7C,0x00,0x7F,0xC0,0x03,0xC0,0x00,
0x7C,0x00,0x3F,0xE0,0x07,0x80,0x00,0x7C,0x00,0x1F,0xFC,0x0F,0x00,0x00,0x7C,0x00,
0x0F,0xFC,0x1E,0x00,0x00,0x7C,0x00,0x07,0xE0,0x1C,0x00,0x00,0x7C,0x00,0x03,0xC0,
0x38,0x00,0x7F,0xFC,0x00,0x01,0x80,0x00,0x00,0x7F,0xFC,0x00,0x00,0x00,0x00,0x00,
0x0F,0xFC,0x00,0x00,0x00,0x00,0x00,0x03,0xF8,0x00,0x00,0x00,0x00,0x00,0x01,0xF0,
0x00,0x00,0x00,0x00,0x00,0x01,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};


/*--  文字:  印  --*/
/*--  宋体42;  此字体下对应的点阵为:宽x高=56x56   --*/
const unsigned char font1[]=
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xC0,0x00,0x00,0x00,0x00,0x00,0x03,0xE0,
0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x3F,0xF0,0x00,0x00,
0x00,0x00,0x00,0xFF,0xE0,0x00,0x03,0x00,0x01,0x87,0xF8,0x03,0x80,0x03,0xC0,0x01,
0xFF,0xC0,0x03,0xFF,0xFF,0xE0,0x01,0xFC,0x00,0x03,0xFF,0xFF,0xE0,0x01,0xE0,0x00,
0x03,0xC0,0x07,0xC0,0x01,0xE0,0x00,0x03,0xC0,0x07,0xC0,0x01,0xE0,0x00,0x03,0xC0,
0x07,0xC0,0x01,0xE0,0x00,0x03,0xC0,0x07,0xC0,0x01,0xE0,0x00,0x03,0xC0,0x07,0xC0,
0x01,0xE0,0x00,0x03,0xC0,0x07,0xC0,0x01,0xE0,0x00,0x03,0xC0,0x07,0xC0,0x01,0xE0,
0x00,0x03,0xC0,0x07,0xC0,0x01,0xE0,0x00,0x03,0xC0,0x07,0xC0,0x01,0xE0,0x00,0x03,
0xC0,0x07,0xC0,0x01,0xE0,0x03,0x03,0xC0,0x07,0xC0,0x01,0xE0,0x07,0x83,0xC0,0x07,
0xC0,0x01,0xFF,0xFF,0xC3,0xC0,0x07,0xC0,0x01,0xFF,0xFF,0xE3,0xC0,0x07,0xC0,0x01,
0xE0,0x00,0x03,0xC0,0x07,0xC0,0x01,0xE0,0x00,0x03,0xC0,0x07,0xC0,0x01,0xE0,0x00,
0x03,0xC0,0x07,0xC0,0x01,0xE0,0x00,0x03,0xC0,0x07,0xC0,0x01,0xE0,0x00,0x03,0xC0,
0x07,0xC0,0x01,0xE0,0x00,0x03,0xC0,0x07,0xC0,0x01,0xE0,0x00,0x03,0xC0,0x07,0xC0,
0x01,0xE0,0x00,0x03,0xC0,0x07,0xC0,0x01,0xE0,0x00,0x03,0xC0,0x07,0xC0,0x01,0xE0,
0x00,0x03,0xC0,0x07,0xC0,0x01,0xE0,0x00,0x73,0xC0,0x07,0xC0,0x01,0xE0,0x03,0xF3,
0xC0,0x07,0xC0,0x01,0xE0,0x3F,0x83,0xC0,0x07,0xC0,0x01,0xE1,0xFE,0x03,0xC7,0xFF,
0xC0,0x01,0xFF,0xF0,0x03,0xC1,0xFF,0xC0,0x03,0xFF,0xC0,0x03,0xC0,0x7F,0x80,0x03,
0xFF,0x00,0x03,0xC0,0x1F,0x00,0x01,0xFC,0x00,0x03,0xC0,0x0E,0x00,0x01,0xF0,0x00,
0x03,0xC0,0x00,0x00,0x00,0xE0,0x00,0x03,0xC0,0x00,0x00,0x00,0x40,0x00,0x03,0xC0,
0x00,0x00,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,
0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x00,0x00,
0x00,0x03,0xC0,0x00,0x00,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x00,0x00,0x00,0x03,
0xC0,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};


/*
函数功能: 针对BMP图片实现的画点函数
函数参数:
	char *bmp_mem  :表示BMP图片RGB颜色数据的首地址
	int x
	int y
	int color	   :画点的颜色值
	
	BMP_DrawPoint(bmp_mem,100,100,0);
*/
unsigned int bmp_Width; //保存BMP图片的宽度
void BMP_DrawPoint(unsigned char *bmp_mem,int x,int y,int color)
{
	unsigned char *rgb=(unsigned char *)(bmp_mem+y*bmp_Width*3+x*3);
	*rgb=color>>0&0xFF;
	*(rgb+1)=color>>8&0xFF;
	*(rgb+2)=color>>16&0xFF;
}

/*
函数功能: 在BMP图片的指定位置添加字符串
说明: 传入的取模字体必须是8的倍数(宽度和高度是相等)
*/
void BMP_ShowString(unsigned char *bmp_mem,unsigned char *font,int x,int y,int size,int color)
{
	int i,j;
	int x0=x;
	unsigned char data;
	for(i=0;i<size/8*size;i++)
	{
		data=font[i];
		for(j=0;j<8;j++)
		{
			if(data&0x80) //为真表示需要画字体颜色
			{
				BMP_DrawPoint(bmp_mem,x0,y,color);
			}
			data<<=1;
			x0++; 
		}
		if((x0-x)==size)
		{
			x0=x;
			y++;
		}
	}
}


/*
函数功能: 添加水印
函数参数:
		char *src_BmpFile     :BMP图片源文件
		char *new_BmpFile     :新文件
返回值  :0表示成功,其他值失败
*/
int Add_BMP(char *src_BmpFile,char *new_BmpFile)
{
	/*1. 打开源文件*/
	int err=0;
	FILE *bmp_file=fopen(src_BmpFile,"rb");
	if(bmp_file==NULL)
	{
		err=1;
		goto ERROR;
	}
	
	/*2. 图片参数获取*/
	struct tagBITMAP_FILE_HEADER src_head; //BMP文件头
	memset(&src_head,0,sizeof(struct tagBITMAP_FILE_HEADER));
	if(fread(&src_head,1,sizeof(struct tagBITMAP_FILE_HEADER),bmp_file)!=sizeof(struct tagBITMAP_FILE_HEADER))
	{
		err=2;
		goto ERROR;
	}
	
	if(src_head.bfType!=0x4d42) //判断类型
	{
		err=3;
		goto ERROR;
	}
	
	struct tagBITMAP_INFO_HEADER src_info; //BMP图像参数
	memset(&src_info,0,sizeof(struct tagBITMAP_INFO_HEADER));
	if(fread(&src_info,1,sizeof(struct tagBITMAP_INFO_HEADER),bmp_file)!=sizeof(struct tagBITMAP_INFO_HEADER))
	{
		err=4;
		goto ERROR;
	}
	
	if(src_info.biBitCount!=24) //判断颜色位数
	{
		err=5;
		goto ERROR;
	}
	
	/*3. 创建新图片*/
	FILE *new_file=fopen(new_BmpFile,"wb");
	if(new_file==NULL)
	{
		err=6;
		goto ERROR;
	}
	
	/*3.1 创建BMP文件头*/
	fwrite(&src_head,1,sizeof(struct tagBITMAP_FILE_HEADER),new_file);
	
	/*3.2 创建BMP图像参数*/
	fwrite(&src_info,1,sizeof(struct tagBITMAP_INFO_HEADER),new_file);

	/*3.3 实现图片的水印添加*/
	int i;
	int lineByte=src_info.biWidth*3; //一行总字节数量
	bmp_Width=src_info.biWidth; //保存BMP图片的宽度
	if(lineByte%4)lineByte++;
	int offset=lineByte*(src_info.biHeight-1)+src_head.bfOffBits;
	unsigned char *data_p=malloc(lineByte*src_info.biHeight); //申请存放RGB数据的空间
	unsigned char *bmp_mem=data_p; //保存RGB数据的首地址
	if(data_p==NULL)
	{
		err=7;
		goto ERROR;
	}
	
	/*3.4 从BMP图片的文件最后一行依次读取数据,存放到缓冲区*/
	for(i=0;i<src_info.biHeight;i++)
	{
		fseek(bmp_file,offset,SEEK_SET);
		fread(data_p,1,lineByte,bmp_file);
		data_p+=lineByte; //指针向下偏移
		offset-=lineByte;
	}
	
	/*3.5 添加水印*/
	BMP_ShowString(bmp_mem,(unsigned char*)font0,40,40,56,0xFF0033);
	BMP_ShowString(bmp_mem,(unsigned char*)font1,40+56,40,56,0xFF0033);

	/*3.6 将数据写入到文件*/
	offset=lineByte*(src_info.biHeight-1)+src_head.bfOffBits;
	data_p=bmp_mem; //指针归位
	for(i=0;i<src_info.biHeight;i++)
	{
		fseek(new_file,offset,SEEK_SET);
		fwrite(data_p,1,lineByte,new_file);
		data_p+=lineByte; //指针向下偏移
		offset-=lineByte;
	}
ERROR:	
	if(bmp_mem)free(bmp_mem);
	if(bmp_file)fclose(bmp_file);
	if(new_file)fclose(new_file);
	return err;
}


int main(int argc,char **argv)
{
	char cmd_buff[100];
	if(argc!=3)
	{
		printf("参数格式: ./app <源bmp图片名称> <新bmp图片名称>\n");
		return 0;
	}
	
	//添加水印
	int err=Add_BMP(argv[1],argv[2]);
	if(err)
	{
		printf("图片水印添加失败!\n");
	}
	else
	{
		printf("图片水印添加成功,新图片名称:%s\n",argv[2]);
		sprintf(cmd_buff,"eog %s",argv[2]);
		system(cmd_buff);
	}
	return 0;
}

学习Makefile

1.​ 学习什么是目标文件: 该如何定义

2.​ 学习什么是目标依赖文件:该如何定义

3.​ Makefile本身推导规则: 如何根据目标和目标依赖文件去进行编译生成目标。

4.​ 学习特殊变量的定义和功能使用: VPATH\ CC\ CFLAGS

5.​ 条件判断语句、常用的几个函数 $(Shell ls)。

6.​ 自动化编译的符号: $@ $< $^ %

make <参数> -n表示调试不编译 -s 隐藏命令的输出


关于make命令运用时传递的参数:

make abc=123 app -ns


Shell脚本编程

Shell脚本: 是一个编程语言(脚本类型的编程语言、解释类型编程语言)

变量、for循环、while循环、if语言、switch语句、函数….

​ Linux开发: 侧重于驱动开发、侧重于运维开发。




【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。