How can I manually read PNG files in C++? -
portable network graphics overview
the general layout of given png file looks this:
file header: 8-byte signature.
chunks: chunks of data ranging image properties actual image itself.
the problem
i want read png files in c++ without using external libraries. want gain deeper understanding of both png format , c++ programming language.
i started off using fstream
read images byte-by-byte, can't past header of png file. try using read( char*, int )
put bytes char
arrays, read
fails on every byte after header.
as seen above, think program gets caught on end-of-file 1a
byte. i'm developing on windows 7 windows 7 , linux machines.
some of (old) code
#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 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 header file.read( data, size ); data[ size ] = '\0'; std::cout << "data size: " << std::strlen( data ) << std::endl; }
the output similar this:
attempting open image.png file size: 1768222 data size: 0
the file size correct, data size incorrect. note try skip header (avoid end-of-file character) , account when declaring size of char* data
.
here data size values when modify file.seekg( ... );
line accordingly:
file.seekg( n ); data size ---------------- --------- 0 8 1 7 2 6 ... ... 8 0 9 0 10 0
some of new code
#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 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 header file.read( data, size ); data[ size ] = '\0'; std::cout << "data size: " << ((unsigned long long)file.tellg() - 8) << std::endl; }
i modified data size:
line. thing note output of data size:
line close maximum value of whatever type
cast file.tellg()
to.
your (new) code contains 2 essential errors:
data = new char[ size - 8 + 1 ]; file.seekg( 8 ); // skip header file.read( data, size ); // <-- here data[ size ] = '\0'; // <-- and here
first off, want read data without 8 byte prefix, , allocate right amount of space (not really, see further). @ point, size
still holds total amount of bytes of file, including 8 byte prefix. since ask read size
bytes , there size-8
bytes remaining, file.read
operation fails. don't check errors , not notice file
invalidated @ point. error check should have seen this:
if (file) std::cout << "all characters read successfully."; else std::cout << "error: " << file.gcount() << " read";
because file
invalid point on, operations such later file.tellg()
return -1
.
the second error data[size] = '\0'
. buffer not large; should data[size-8] = 0;
. currently, writing memory beyond allocated earlier, causes undefined behavior , may lead problems later on.
but last operation shows thinking in terms of character strings. png file not string, binary stream of data. allocating +1
size , setting value 0
(with unnecessary "character-wise" way of thinking, '\0'
) useful if input file of string type – say, plain text file.
a simple fix current issues (well, , add error checking file operations):
file.read( data, size-8 );
however, advise @ simpler file format first. png file format compact , documented; versatile, complicated, , contains highly compressed data. beginner way hard.
start easier image format. ppm
deliberately simple format, start with. tga
, old easy, introduces several more concepts such bit depths , color mapping. microsoft's bmp
has nice little caveats can still considered 'beginner friendly'. if interested in simple compression, basic run length encoding of pcx
starting point. after mastering in gif
format, uses harder lzw compression.
only if succeed in implementing parsers these, may want @ png again.
Comments
Post a Comment