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

290 阅读12分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第20天,点击查看活动详情

主要是介绍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开发: 侧重于驱动开发、侧重于运维开发。