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

2023-11-09

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

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

//图片的参数结构体   单位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. 执行
在这里插入图片描述

5. 对比
在这里插入图片描述

6. 非原创

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux&C语言简单实现图片加马赛克-标准IO实现 的相关文章

  • 如何阅读shell命令的源代码?

    我想阅读编写linux命令的实际源代码 我已经获得了一些使用它们的经验 现在我认为是时候与我的机器进行更深层次的交互了 我在这里找到了一些命令http directory fsf org wiki GNU http directory fs
  • 如何仅将整个嵌套目录中的头文件复制到另一个目录,在复制到新文件夹后保持相同的层次结构

    我有一个目录 其中有很多头文件 h 和其他 o 和 c 文件以及其他文件 这个目录里面有很多嵌套的目录 我只想将头文件复制到一个单独的目录 并在新目录中保留相同的结构 cp rf oldDirectory newDirectory将复制所有
  • 是否有可能在linux中找到包含特定文本的文件?

    考虑这种情况 我在文件夹 Example 下有很多文件 如果我需要找到一个包含特定短语 如 Class Example 的文件 我该如何使用 Linux shell 来做到这一点 linux中有类似 定位 的函数可以做到这一点吗 Thank
  • linux下如何获取昨天和前天?

    我想在变量中获取 sysdate 1 和 sysdate 2 并回显它 我正在使用下面的查询 它将今天的日期作为输出 bin bash tm date Y d m echo tm 如何获取昨天和前天的日期 这是另一种方法 对于昨天来说 da
  • Bash 脚本 - 迭代 find 的输出

    我有一个 bash 脚本 其中需要迭代 find 命令输出的每一行 但似乎我正在迭代 find 命令中的每个单词 以空格分隔 到目前为止我的脚本看起来像这样 folders find maxdepth 1 type d for i in f
  • Linux、ARM:为什么仅当启动时存在 I2C GPIO 扩展器时才创建 gpiochip

    在 imx6sx 硬件平台 NXP 嵌入式 ARM 上使用 Linux 3 14 52 问题是设备树中指定的 PCF8575 I2C GPIO 扩展器不会实例化为 sys class gpio 结构中的设备 除非它们在内核启动期间存在 这些
  • 如何从 Linux 的 shell 中删除所有以 ._ 开头的文件?

    确实如标题所示 我已将许多文件从 Mac 复制到 Raspberry Pi 这导致了许多以前缀开头的多余文件 我想删除以以下开头的文件夹中的每个文件 我该怎么做 尝试类似的方法 cd path to directory rm rf 或者 如
  • Linux命令列出所有可用命令和别名

    是否有一个 Linux 命令可以列出该终端会话的所有可用命令和别名 就好像您输入 a 并按下 Tab 键一样 但针对的是字母表中的每个字母 或者运行 别名 但也返回命令 为什么 我想运行以下命令并查看命令是否可用 ListAllComman
  • 是否从页面缓存中的脏页面进行文件读取?

    当字节写入文件时 内核不会立即将这些字节写入磁盘 而是将这些字节存储在页缓存中的脏页中 回写缓存 问题是 如果在脏页刷新到磁盘之前发出文件读取 则将从缓存中的脏页提供字节 还是首先将脏页刷新到磁盘 然后进行磁盘读取以提供字节 将它们存储在进
  • 如何从类似于 eclipse 的命令行创建可运行的 jar 文件

    我知道 eclipse 会生成一个可运行的 jar 文件 其中提取并包含在该 jar 文件中的所有库 jar 文件 从命令提示符手动创建 jar 文件时如何执行类似的操作 我需要将所有 lib jar 解压到类文件夹中吗 目前我正在使用 j
  • python:numpy 运行脚本两次

    当我将 numpy 导入到 python 脚本中时 该脚本会执行两次 有人可以告诉我如何阻止这种情况 因为我的脚本中的所有内容都需要两倍的时间 这是一个例子 usr bin python2 from numpy import print t
  • 如何从linux命令行运行.exe可执行文件? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我在 Windows 中有一个 abc exe 可执行文件 我可以使用 DOS 命令提示来执行此应用程序 并为其提供一些运行时变量 我想从
  • 无法仅在控制台中启动 androidstudio

    你好 我的问题是下一个 我下载了Android Studio如果我去 路径 android studio bin 我执行studio sh 我收到以下错误 No JDK found Please validate either STUDIO
  • 如何查明 Ubuntu 上安装了哪个版本的 GTK+?

    我需要确定 Ubuntu 上安装了哪个版本的 GTK 男人似乎不帮忙 这个建议 https stackoverflow com a 126145 会告诉您安装了哪个 2 0 的次要版本 不同的主要版本将具有不同的包名称 因为它们可以在系统上
  • git在Windows和Linux之间切换后强制刷新索引

    我有一个Windows和Linux共享的磁盘分区 格式 NTFS 它包含一个 git 存储库 约 6 7 GB 如果我只使用Windows or 只使用Linux操作 git 存储库一切正常 但是每次切换系统的时候git status命令将
  • 伊迪德信息

    重新定义问题 有什么方法可以获取所连接显示器的序列号吗 我想收集显示器的Eid信息 当我使用 logverbose 选项运行 X 时 我可以从 xorg 0 log 文件中获取它 但问题是 如果我切换显示器 拔出当前显示器 然后插入另一个显
  • Inotify linux 监视子目录

    是否可以以这种模式监视目录 storage data usernames Download gt storage data Download 我需要监视每个用户的下载文件夹中是否进行了更改 也许我需要创建所有路径的列表 将其放入数组中 并在
  • Bash 方法的返回值总是模 256

    我有一个 bash 脚本方法 它返回输入值 然而 返回值始终是模 256 的值 我用 google 搜索了一段时间 发现this http www tldp org LDP abs html exitcodes html文章说它总是以 25
  • 从 TypeScript 运行任何 Linux 终端命令?

    有没有办法直接从 TypeScript 类中执行 Linux 终端命令 这个想法是做类似的事情 let myTerminal new LinuxTerminal let terminalResult myTerminal run sudo
  • 如何在特定 systemd 服务重新启动时触发自定义脚本运行

    我想知道如何安排自定义脚本在重新启动服务时运行 我的用例是 每当重新启动 Tomcat 服务时 我都必须运行多个命令 我想知道是否有一种方法可以编写脚本并安排它在重新启动 Tomcat 服务时运行 我已将 tomcat 脚本设置为 syst

随机推荐