【发布时间】:2015-09-13 19:22:18
【问题描述】:
便携式网络图形概述
任何给定 PNG 文件的一般布局如下所示:
文件头:一个 8 字节的签名。
块:从图像属性到实际图像本身的数据块。
问题
我想在不使用任何外部库的情况下读取 C++ 中的 PNG 文件。我想这样做是为了更深入地了解 PNG 格式和 C++ 编程语言。
我开始使用 fstream 逐字节读取图像,但我无法通过任何 PNG 文件的标题。我尝试使用read( char*, int ) 将字节放入char 数组中,但read 在标头之后的每个字节上都失败了。
如上所示,我认为我的程序总是被文件结尾1A 字节捕获。我正在为 Windows 7 和 Linux 机器在 Windows 7 上进行开发。
我的一些(旧)代码
#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在第一个空终止符处停止,您假设添加到缓冲区末尾的空终止符是唯一的。将二进制数据视为文本字符串通常不是一个好主意。 -
@CaptainObvlious 但是我怎样才能获得这些数据大小值呢?你说的有点道理,但似乎也暗示根据这些值,标题后面的每个值都是空终止符:file.seekg(0), data size: 8; file.seekg(1),数据大小:7; file.seekg(2),数据大小:6; ... file.seekg(8),数据大小:0; file.seekg(9),数据大小:0; file.seekg(10),数据大小:0; ...
-
我并不是在暗示 。存储在 PNG 中的数据应被视为二进制数据,这意味着您永远不应假设空终止符,
strlen将是正确的方法。您需要检查 PNG 的文件格式并开始解释数据的实际情况,而不是假设它只是一堆字符串。 -
@user3745189
I want to read PNG files in C++ without using anything other than STL您的代码没有使用 STL 中的任何内容。如果是这样,至少你会用std::vector替换new[] -
@user3745189 图像数据本身可以有空字符。图像数据中的那些空字符与字符串终止无关——它只是那里的数据。因此,您不要使用在 null 处停止的字符串函数。
标签: c++ file-io png fstream ifstream