这个是在知乎上看到的大神写的文章,如果是学习C语言入门的,我觉得可以从这个入手,特别是对图像感兴趣的。
文章中提到的「我」,指的是「Milo Yip」大神。
1. 什么是png格式图片?
相对地,PNG(Portable Network Graphics)就是一个广为人知的图片格式。如果可以把影像直接储存成 PNG,不是更理想么?
然而,在 C/C++ 中写入 PNG 一般需要链接一些程序库,例如 PNG 的标准参考程序库是 libpng。它很强大,支持 PNG 所有功能,但对于初学者而言,配置、编译并学习如何使用这些程序库,可能已足够打消动手的念头。
可以简单一点么?
2. svpng
为此,我在周末尝试写一个极简的 C 函数 Github miloyip/svpng(save PNG 的缩写),它仅能写入 24-bit RGB 或 32-bit RGBA、无压缩的 PNG。它只有一个 32 行代码的函数。
github地址:
https://github.com/miloyip/svpng
用法如下:
#include "svpng.inc"void test_rgb(void) {unsigned char rgb[256 * 256 * 3], *p = rgb;unsigned x, y;FILE *fp = fopen("rgb.png", "wb");for (y = 0; y < 256; y++)for (x = 0; x < 256; x++) {*p++ = (unsigned char)x; /* R */*p++ = (unsigned char)y; /* G */*p++ = 128; /* B */}svpng(fp, 256, 256, rgb, 0);fclose(fp);
}
就会输出这个 rgb.png 文件:
这个函数的声明很简单,缺省配置下是这样的:
/*!\brief 以 PNG 格式存储 RGB/RGBA 影像\param out 输出流(缺省使用 FILE*)。\param w 影像宽度。(<16383)\param h 影像高度。\param img 影像像素数据,内容为 24 位 RGB 或 32 位 ARGB 格式。\param alpha 影像是否含有 alpha 通道。
*/
void svpng(FILE* out, unsigned w, unsigned h, const unsigned char* img, int alpha);
相信这样的函数时使对初学者而言,也极易使用。也不需要另外生成程序库,只要复制到项目便可使用。
3. 代码实现
这里简单介绍实现要点,对此没兴趣的读者也可略过。
根据 Portable Network Graphics (PNG) Specification (Second Edition) 「www.w3.org」,PNG 文件由多个 chunk 组成。每个 chunk 的类型以 4 个字符表示。最基本的 PNG 文件内容是:
8 字节 magic number:用于识别 PNG 格式
IHDR(Image Header) chunk:描述影像的维度、色彩深度、色彩格式、压缩类型等
IDAT(Image Data)chunk:存储影像的像素数据
IEND(Image End)chunk:PNG数据流结束
每个 chunk 的结构是:
chunk 内容长度(4 字节)
chunk 类型(4 字节)
chunk 内容
chunk 的 CRC(包括类型和内容)
PNG 里的数据是以大端(big endian)编码的,但在 IDAT 中,每个 block 的长度则以小端存储。另外,实现的难点之一,是要同时实现 CRC-32 及 Adler-32 校验和(checksum)的生成。
编码实现如下(文字版请移玉步至 svpng.inc):
为了减少代码大小,使用宏去避免加入多个函数。另外,为了简化实现,把每一行像素写成一个 block,这样可能会浪费一点空间,但对于这函数而言也不是问题。
4. 结语
本文介绍了一个极简的 C 函数 svpng,方便在 C/C++ 中把图像存储成 PNG 文件,并简介了当中的实现。希望读者能利用此函数,进入计算机图形学之门。
===
文中的 inc 而不是.h,是因为inc 是对方法的实现,而不是简单的声明。
unsigned char rgb[256 * 256 * 3] ,可能有的人不明白为什么数组要这样声明,一个像素点是通过{R,G,B}三色值表示的,所以后面有一个3,但是一张图片,是包含有长和宽的,也就是前面的256*256,就是这张图片的长和宽。实际上的图片是这样排列的 { R, G, B, R, G, B, ... } 的形式,从上至下,左至右。
#推荐阅读#
专辑|Linux文章汇总
专辑|程序人生
专辑|C语言
我的知识小密圈
关注公众号,后台回复「1024」获取学习资料网盘链接。
欢迎点赞,关注,转发,在看,您的每一次鼓励,我都将铭记于心~
嵌入式Linux
微信扫描二维码,关注我的公众号