写点什么

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

作者:DS小龙哥
  • 2022 年 6 月 13 日
  • 本文字数:6980 字

    阅读完需:约 23 分钟

主要是介绍 BMP 结构、利 BMP 图片练习文件编程操作,通过文件编程接口对 BMP 图片完成读写,添加水印、翻转等操作。

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

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


16 位。


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


【3】实现图片 4 种翻转效果: 上、下、左、右。


【4】给图片的指定位置添加水印


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


比如: xxx 路口 20181008 11:04


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


【5】目录练习: 拷贝目录下所有文件(指定后缀的文件)到指定目录下,考虑一层目录。


多层目录拷贝。


【6】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 本身是一个用 C 语言编写的程序,它是用户使用 Unix/Linux 的桥梁,用户的大部分工作都是通过 Shell 完成的。 Shell 既是一种命令语言,又是一种程序设计语言。


作为命令语言,它交互式地解释和执行用户输入的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。


它虽然不是 Unix/Linux 系统内核的一部分,但它调用了系统核心的大部分功能来执行程序、建立文件并以并行的方式协调各个程序的运行。因此,对于用户来说, shell 是最重要的实用程序,深入了解和熟练掌握 shell 的特性极其使用方法,是用好 Unix/Linux 系统的关键。


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


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


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

发布于: 刚刚阅读数: 4
用户头像

DS小龙哥

关注

之所以觉得累,是因为说的比做的多。 2022.01.06 加入

熟悉C/C++、51单片机、STM32、Linux应用开发、Linux驱动开发、音视频开发、QT开发. 目前已经完成的项目涉及音视频、物联网、智能家居、工业控制领域

评论

发布
暂无评论
Linux开发_介绍BMP图片上下翻转、添加水印_6月月更_DS小龙哥_InfoQ写作社区