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

Popular posts from this blog

OpenCV OpenCL: Convert Mat to Bitmap in JNI Layer for Android -

android - org.xmlpull.v1.XmlPullParserException: expected: START_TAG {http://schemas.xmlsoap.org/soap/envelope/}Envelope -

python - How to remove the Xframe Options header in django? -