给图片打马赛克

原理:将图片分成若干个块,每个块的颜色都修改成第一个点的颜色,这样就实现了将图片打马赛克。

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.需要注意的是当你的块设置的越小,图片会变得更加清晰的,相反,块越大,图片会更加的模糊。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值