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;
}
6. 非原创