1,问题需求
针对 bmp 格式的24位图图片的文件进行马赛克打码处理。
2,bmp图片的简单介绍
整体数据段:
数据段名称 | 大小(Byte) |
bmp 文件头 | 14 |
位图 信息头 | 40 |
调色板 | 由颜色索引数决定 |
位图数据 | 由图像尺寸决定 |
bmp 文件头部分所需数据:
在前14个字节的bmp的头文件,偏移两个字节后的四个字节是该图片的大小,
变量名 | 地址偏移 | 大小 | 作用 |
bf_size | 0002h | 4 Bytes | 说明位图文件的大小,字节为单位 |
位图 信息头部分所需数据:
14个字节的头文件之后就是40个字节大小的文件信息头,可以读取到图像的高度,宽度--像素为单位。
变量名 | 地址偏移 | 大小 | 作用 |
biwidth | 0012h | 4Bytes | 说明图像的宽度,像素为单位 |
biheight | 0016h | 4Bytes | 说明图像的高度,像素为单位 |
以上信息是从读bmp文件所得到的必备信息。
说明:24位图信息,像素的问题,1个像素点 分为红绿蓝 也就是R G B,一个颜色占一个字节 0-255,所以一个像素点占三个字节。
3整体思想:
将图片分为几块例如每块都是10×10的大小,每一个10×10的像素块,都取第一个像素点的颜色字节,将其填充。循环执行即可。
4 代码实现:
#include <head.h>//这里将部分头文件加到我自己写的一个库里了,可以通过man手册查看所需头文件
#include <stdlib.h>
//需求:使用标准IO,进行对图片的马赛克处理。
typedef struct{ //定义图片信息的结构体
unsigned int img_size;
unsigned int img_width;
unsigned int img_high;
unsigned short img_bitcount;
}image_info_t;
typedef struct{ //定义红绿蓝颜色的结构体
unsigned char b;
unsigned char g;
unsigned char r;
}point_t;
//函数功能:打印获取到的图片信息,大小,高度,宽度。
//函数参数:图片信息结构体指针
//返回值:无
void show_image_info(image_info_t *info)
{
printf("size = %d,width = %d,high = %d,bitcount = %d\n",
info->img_size,info->img_width,info->img_high,info->img_bitcount);
}
//函数功能:获取图片的信息,根据bmp详解获取图片大小,高度,宽度信息
//函数参数:所打开文件的描述符,图片信息的结构体指针
//返回值:无
void get_image_info(FILE*fp,image_info_t *info)
{
fseek(fp,2,SEEK_SET);
fread(&info->img_size,1,4,fp);
fseek(fp,18,SEEK_SET);
fread(&info->img_width,1,4,fp);
fread(&info->img_high,1,4,fp);
fseek(fp,2,SEEK_CUR);
fread(&info->img_bitcount,1,2,fp);
}
//函数功能:拷贝源文件,不在原有的图片上进行修改。
//函数参数:源文件和目标文件的文件描述符
//返回值:无
void copy_image_file(FILE*sfp,FILE*dfp)
{
int ret;
char buf[1024] = {0};
while(!(feof(sfp)||ferror(sfp))){
ret = fread(buf,1,sizeof(buf),sfp);
fwrite(buf,1,ret,dfp);
}
return;
}
//函数功能:图片马赛克处理
//函数参数:打开文件的描述符,图片信息的结构体指针,像素块的宽和高
//返回值:无
void set_image_mosaic(FILE *fp,image_info_t *info,int x,int y)
{
int i,j,k,w;
point_t color = {0,0,0xff};
char *buffer = (char *)malloc((info->img_width)*(info->img_high)*3);//使用malloc分配空间
//1.将图像读取到buffer内
fseek(fp,54,SEEK_SET);
fread(buffer,1,(info->img_size-54),fp);
//2.修改
//i:整体的高/10
//j:整体的宽除以10
//k:块的高
//w:块的宽
// 整体是需要四个循环构成,首先是获取像素块的第一个像素点,例如传入的是10×10的像素块,第一个像素点就是在第一个像素块内,第二个像素块的第一个像素点需要根据前一个像素块的第一个像素点进行找到,j×10×3,第一排的像素块循环结束后,需要到第二排像素块去继续第一排的操作,需要 i×10×整体的宽度×3
for(i=0;i<info->img_high/y;i++){
for(j=0;j<info->img_width/x;j++){
color = *(point_t *)(buffer+(j*3*x)+(i*y*info->img_width*3));//获取第一个像素点
for(k=0;k<y;k++){//像素块内的操作
for(w=0;w<x;w++){
*(point_t*)(buffer+w*3+(k*info->img_width*3)+
(j*3*x)+(i*y*info->img_width*3)) = color;
}
}
}
}
//3.重新将打好马赛克的buf中的图像写到目标文件内。
fseek(fp,54,SEEK_SET);
fwrite(buffer,1,(info->img_size-54),fp);
}
int main(int argc, char const *argv[])
{
FILE *sfp,*dfp;
int size;
image_info_t info;
char new_name[20] = {0};
if(argc != 2){
fprintf(stderr,"input error,try again\n");
fprintf(stderr,"usage:./a.out xxxx.bmp\n");
return -1;
}
//1.打开文件并拷贝文件
if((sfp = fopen(argv[1],"r"))==NULL)
PRINT_ERR("open error");
snprintf(new_name,sizeof(new_name),"new_%s",argv[1]);
if((dfp = fopen(new_name,"w+"))==NULL)
PRINT_ERR("open error");
copy_image_file(sfp,dfp);
//2.获取图片的信息
get_image_info(dfp,&info);
show_image_info(&info);
//3.尝试打马赛克
set_image_mosaic(dfp,&info,10,10);
fclose(sfp);
fclose(dfp);
return 0;
}