Linux&C语言简单实现图片加马赛克-标准IO实现

1. 基于C语言实现,标准IO练习
2. 图片格式bmp
BMP图片格式详解
(获取图片前54个字节中有用的信息链接)
3. 代码实现

//标准IO实现
#include  // Shift  +  Alt  + F     实现代码的对齐;
// malloc函数的头文件
#include 

//图片的参数结构体   单位Bytes
typedef struct
{
    unsigned int img_size;       //图片的大小
    unsigned int img_width;      //图片的宽
    unsigned int img_high;       //图片的高
    unsigned short img_bitcount; //一个像素点占用的bit(24bit)当biBitCount=24时,1个像素占3个字节;
} image_info_t;

// RGB颜色参数
typedef struct
{
    unsigned char b; // B
    unsigned char g; // G
    unsigned char r; // 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);
}*/

//值传递
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);
}

void get_image_info(FILE *fp, image_info_t *info)
{
    //修改光标的位置
    fseek(fp, 2, SEEK_SET);           //从文件的开头向后偏移2个字节
    fread(&info->img_size, 1, 4, fp); //图片的大小

    fseek(fp, 18, SEEK_SET);           // biWidth = biSize:002h+4Bytes + 012h
    fread(&info->img_width, 1, 4, fp); //图片的宽

    // biHeight = biSize:002h+4Bytes + biWidth:012h+4Bytes = 22
    // fseek(fp, 22, SEEK_SET);//紧接着,无需修改光标的位置也可继续读
    fread(&info->img_high, 1, 4, fp); //读取图片的高

    // biSizeImage=biSize:002h+4Bytes + 022h= 28   此时上面执行完后在 26  (从文件的开头向后偏移26个字节)
    //还需要  从光标当前位置向后偏移2个字节
    fseek(fp, 2, SEEK_CUR);               //<==>fseek(fp, 28, SEEK_SET); 从文件的开头向后偏移28个字节
    fread(&info->img_bitcount, 1, 2, fp); //像素点占用的bit
}

void copy_image_file(FILE *sfp, FILE *dfp)
{
    int ret;
    char buf[1024] = {0};
    /*成功返回读取到的项目的个数,如果是失败或者读取到的文件的结尾返回值是要小于nnemb或者0
 读取到文件的结尾需要通过feof(fp)或者错误通过ferror(fp)来判断*/
    while (!(feof(sfp) || ferror(sfp)))
    {
        // fread(保存读取到数据的首地址,每一项的大小, 项的个数,文件指针);成功返回读取到的项目的个数
        ret = fread(buf, 1, sizeof(buf), sfp);
        // fwrite(数据的首地址,每一项的大小, 项的个数,文件指针);成功返回写入的项目的个数
        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}; //{B,G,R}
    //保存读取到的数据
    char *buffer = (char *)malloc((info->img_width) * (info->img_high) * 3);

    // 1.将图像读取回来  (跳过图片的文件头、信息头)54Byte
    fseek(fp, 54, SEEK_SET);
    fread(buffer, 1, (info->img_size - 54), fp);
    // 2.修改buffer
    //传入 x y

    // i:整体的高/10  (共有行数)
    for (i = 0; i < info->img_high / y; i++)
    {
        // j:整体的宽除以10 (共有列数)
        for (j = 0; j < info->img_width / x; j++)
        {
            //读取小方块中最左上角的像素点   //当biBitCount=24时,1个像素占3个字节;
            color = *(point_t *)(buffer + (j * 3 * x) + (i * y * info->img_width * 3));
            // k:小方块的高(行)
            for (k = 0; k < y; k++)
            {
                // w:小方块的宽(列)
                for (w = 0; w < x; w++)
                {
                    //将小方块的各个像素赋值==最左上角的像素点//当biBitCount=24时,1个像素占3个字节;
                    *(point_t *)(buffer + w * 3 + (k * info->img_width * 3) +
                                 (j * 3 * x) + (i * y * info->img_width * 3)) = color;
                }
            }
        }
    }

    // 3.重新将图像写回去
    fseek(fp, 54, SEEK_SET); //修改光标的位置回到原位
    fwrite(buffer, 1, (info->img_size - 54), fp);
    //释放地址空间的
    free(buffer);
}
int main(int argc, char const *argv[])
{
    FILE *sfp, *dfp;
    int size;
    image_info_t info; //图片的参数结构体
    char new_name[20] = {0};

    if (argc != 2)
    { //命令行输入./a.out xxxx.bmp
        fprintf(stderr, "input error,try again\n");
        fprintf(stderr, "usage:./a.out xxxx.bmp\n");
        return -1;
    }
    // 1.打开文件并拷贝文件 milaoshu.bmp
    if ((sfp = fopen(argv[1], "r")) == NULL)
    {
        perror("open error");
        return -1;
    }

    //构造一个新图片的字符串  new_milaoshu.bmp
    snprintf(new_name, sizeof(new_name), "new_%s", argv[1]);
    //存放首地址                格式化的控制格式
    //打开新图片,如果不存在就创建,如果存在就清空
    if ((dfp = fopen(new_name, "w+")) == NULL) // w+ 读写
    {
        perror("open error");
        return -1;
    }

    //图片的拷贝,将milaoshu.bmp-->new_milaoshu.bmp
    copy_image_file(sfp, dfp);

    // 2.获取图片前54个字节中有用的信息
    get_image_info(dfp, &info); //传地址直接修改赋值

    // show_image_info(&info);//地址传递
    show_image_info(info); //值传递

    // 3.尝试打马赛克
    // 10,10:代表的是打马赛克每个小方块的大小
    // 10*3= 30
    // 10  = 10行
    set_image_mosaic(dfp, &info, 10, 10);

    // 4.关闭源文件和目标文件
    fclose(sfp);
    fclose(dfp);
    return 0;
}

4. 执行
Linux&C语言简单实现图片加马赛克-标准IO实现_第1张图片

5. 对比
Linux&C语言简单实现图片加马赛克-标准IO实现_第2张图片

6. 非原创

你可能感兴趣的:(Linux&C,c语言,linux)