原理:将图片分成若干个块,每个块的颜色都修改成第一个点的颜色,这样就实现了将图片打马赛克。
1.程序如下:
#include <stdio.h>
#include <stdlib.h>
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 get_image_info(FILE *dfp,image_info_t *info){
fseek(dfp,2,SEEK_SET);
fread(&info->img_size,1,4,dfp);
fseek(dfp,18,SEEK_SET);
fread(&info->img_width,1,4,dfp);
//fseek(dfp,22,SEEK_SET);
fread(&info->img_high,1,4,dfp);
fseek(dfp,2,SEEK_CUR);
//fseek(dfp,28,SEEK_SET);
fread(&info->img_bitcount,1,2,dfp);
}
void print_image_info(image_info_t *info){
printf("image_size=%d image_width=%d image_high=%d image_bitcount=%d\n",
info->img_size,info->img_width,info->img_high,info->img_bitcount);
}
void copy_image_file(FILE *sfp,FILE *dfp){
char buf[1024]={0};
int ret=0;
while(!(feof(sfp)||ferror(sfp))){
ret=fread(buf,1,sizeof(buf),sfp);
fwrite(buf,1,ret,dfp);
}
return ;
}
void set_image_mosaic(FILE *dfp,image_info_t *info,int x,int y){
//分配一块空间,存放图片的信息
char *buf=(char *)malloc((info->img_width)*(info->img_high)*(info->img_bitcount/8));
//定义一个色素
point_t color={0,0,0xff};
int i=0,j=0,h=0,w=0;
//将光标定位到图片调色板开头
fseek(dfp,54,SEEK_SET);
//将图片信息除了文件头54位其他的信息放到开辟的空间里边
fread(buf,1,(info->img_size-54),dfp);
//修改图片
//块循环的次数
for(i=0;i<(info->img_high/x);i++){ //循环图片高度的次数
for(j=0;j<(info->img_width/y);j++){ //循环图片宽度的次数
//获取每一个块的第一个颜色点
color=*(point_t *)(buf+j*(info->img_bitcount/8)*y+(i*x*(info->img_bitcount/8)*(info->img_width)));
//将块里边的其他点修改成其一个点的颜色
for(h=0;h<x;h++){
for(w=0;w<y;w++){
*(point_t *)(buf+w*(info->img_bitcount/8)+(h*(info->img_width)*(info->img_bitcount/8))+(j*(info->img_bitcount/8)*y)+(i*x*(info->img_bitcount/8)*(info->img_width)))=color;
}
}
}
}
//重新将图片读取到dfp中
fseek(dfp,54,SEEK_SET);
fwrite(buf,1,(info->img_size-54),dfp);
}
int main(int argc, char const *argv[])
{
//参数检查
if(argc!=2){
fprintf(stderr,"intput error,try again\n");
fprintf(stderr,"usage: ./a.out srcfile destfile\n");
return -1;
}
//创建两个文件指针
FILE *sfp,*dfp;
image_info_t info;
char new_name[20]={0};
if((sfp=fopen(argv[1],"r"))==NULL){
perror("open srcfile error");
return -1;
}
//格式化输出新的图片名
snprintf(new_name,sizeof(new_name),"new_%s",argv[1]);
if((dfp=fopen(new_name,"w+"))==NULL){
perror("open srcfile error");
return -1;
}
//复制一份图片,以免操作失误,导致图片损坏
copy_image_file(sfp,dfp);
//获取文件信息
get_image_info(dfp,&info);
//打印文件信息
print_image_info(&info);
//尝试打马赛克
set_image_mosaic(dfp,&info,10,10);//最后两个是块高 块宽
fclose(sfp);
fclose(dfp);
return 0;
}
2.实现效果
3.需要注意的是当你的块设置的越小,图片会变得更加清晰的,相反,块越大,图片会更加的模糊。