【AVD】C++ 获取 PNG 图片宽高信息

之前写过一个使用 FFmpeg 类对图片实现了解码、转码、裁剪、缩放等功能,发现比 ImageMagic 快多了。详情见 【AVD】杀鸡用牛刀,FFmpeg API 加载存储图片,比 ImageMagic 和 stb_image 快多了。但是,在文章 【AVD】C++ 不解码获取 JPG 图片宽高、旋转信息等 EXIF 信息 中提到过,如果我们只需要获取图片的宽高信息,而不用解码图片时,现有的 FFmpeg 代码并不能在解码之前得到一些格式的图片,现在已知的 PNG、JPG 均不能获得,而 GIF 是可以在解码前就通过 AVStream->codecpar 获得的。
因此,找了一个直接读文件头的方法来获取 PNG 图片的宽高。这要比用 FFmpeg 对 PNG 图片进行解码后获取其宽高快一些。

PNG 文件头格式

在 Windows 上可以用 UltraEditor、7yuv 等软件 打开一张 png 然后看到它的 HEX 十六进制表示,在 Linux 上可以使用 vi 或 vim 打开一张 png ,然后输入 :%!xxd 查看其十六进制内容。下图是一张 png 图片在 Linux 上的十六进制图:
【AVD】C++ 获取 PNG 图片宽高信息_第1张图片

参考文章 PNG文件头格式解析,我们可以知道,PNG 文件以 89 50 4E 47 0D 0A 1A 0A 开始,是PNG头部署名域,表示这是一个PNG图片。

后面蓝色框中的内容表示了 IHDR 头部的大小,是 13 个字节。

再往后的绿色框内被称为 Chunk Type Code,这里表示了这个 chunk 是个 IHDR。

高亮的 13 个字节就是它的 IHDR 信息了。
【AVD】C++ 获取 PNG 图片宽高信息_第2张图片

根据上图,我们可以得知,该 png 图片的 Width = 0x0000 01d0 = 464,Height = 0x0000 0198 = 408,Bit depth = 0x08 = 8,Color Type = 0x06 = 带α通道真彩色,压缩方法、滤波器方法均为 0,非隔行扫描。

具体实现

因此,拿 C++ 读文件,然后按上述方法去提取相关信息即可:

#include 
using std::ifstream;
using std::string;
unsigned int get_unsigned_int(unsigned char data[4]) {
  	return (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
}
void GetPngWH(string filename) {
  	ifstream fin;
  	fin.open(filename, std::ios_base::binary | std::ios_base::in);
  	if (!fin.good()) {
    	AVLOGE("Error to open file %s, because %d.", filename.c_str(), fin.get());
    	return false;
  	}
  	char data[4];
  	fin.read(data, 4);
  	if (string(data + 1).compare("PNG") != 0) {
    	AVLOGE("File %s is not a png file.", filename.c_str());
    	fin.close();
    	return false;
  	}
  	fin.seekg(8, std::ios_base::cur);
  	fin.read(data, 4);
  	if (string(data).compare("IHDR") != 0) {
    	AVLOGE("Error to find IHDR of the png file %s", filename.c_str());
    	fin.close();
    	return false;
  	}
  	fin.read(data, 4);
  	width_ = get_unsigned_int((unsigned char *)data);
  	fin.read(data, 4);
  	height_ = get_unsigned_int((unsigned char *)data);
  	fin.close();
 }

你可能感兴趣的:(AVD,C++,c++,音视频,图像处理)