可移植网络图形总览
任何给定的PNG文件的常规布局如下:
文件头: 8字节的签名。
块: 数据块,从图像属性到实际图像本身。
问题
我想在C++中读取PNG文件,而不使用任何外部库。我想这样做是为了更深入地了解PNG格式和C++编程语言。
我开始使用fstream
逐字节读取图像,但我无法通过任何PNG文件的标题。我尝试使用read(char*,int)
将字节放入char
数组中,但read
在标题后的每个字节上都失败了。
如上所示,我认为我的程序总是卡在文件结束1A
字节上。我正在Windows 7上开发Windows 7和Linux机器。
一些(旧)代码
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstddef>
const char* INPUT_FILENAME = "image.png";
int main()
{
std::ifstream file;
size_t size = 0;
std::cout << "Attempting to open " << INPUT_FILENAME << std::endl;
file.open( INPUT_FILENAME, std::ios::in | std::ios::binary | std::ios::ate );
char* data = 0;
file.seekg( 0, std::ios::end );
size = file.tellg();
std::cout << "File size: " << size << std::endl;
file.seekg( 0, std::ios::beg );
data = new char[ size - 8 + 1 ];
file.seekg( 8 ); // skip the header
file.read( data, size );
data[ size ] = '\0';
std::cout << "Data size: " << std::strlen( data ) << std::endl;
}
输出结果始终类似于这样:
Attempting to open image.png
File size: 1768222
Data size: 0
文件大小正确,但数据大小明显不正确。请注意,在声明 char* data
的大小时,我试图跳过标题(避免文件结尾字符),并在此考虑。
根据我相应修改 file.seekg(...);
代码行后,以下是一些数据大小值:
file.seekg( n ); data size
---------------- ---------
0 8
1 7
2 6
... ...
8 0
9 0
10 0
我的一些新代码
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstddef>
const char* INPUT_FILENAME = "image.png";
int main()
{
std::ifstream file;
size_t size = 0;
std::cout << "Attempting to open " << INPUT_FILENAME << std::endl;
file.open( INPUT_FILENAME, std::ios::in | std::ios::binary | std::ios::ate );
char* data = 0;
file.seekg( 0, std::ios::end );
size = file.tellg();
std::cout << "File size: " << size << std::endl;
file.seekg( 0, std::ios::beg );
data = new char[ size - 8 + 1 ];
file.seekg( 8 ); // skip the header
file.read( data, size );
data[ size ] = '\0';
std::cout << "Data size: " << ((unsigned long long)file.tellg() - 8) << std::endl;
}
我基本上只修改了Data size:
这一行。需要注意的是,Data size:
行的输出始终非常接近于我将file.tellg()
转换为的任何type
的最大值。
strlen
函数在遇到第一个空字符(null terminator)时停止计算,你假设添加到缓冲区结尾的空字符是唯一的。通常不应将二进制数据视为文本字符串。 - Captain Obvliousstrlen
是正确的方法。您需要检查PNG文件格式并开始解释实际数据而不是假设它只是一堆字符串。 - Captain Obvlious我想在C++中读取PNG文件,而不使用除STL之外的任何东西
。你的代码没有使用STL中的任何内容。如果使用了STL,至少你需要将new[]
替换为std::vector
。 - PaulMcKenzie