PNG File Format and Opportunities of Parallel Programming



Ruben Safir MS Comp Sci

Fall Semester 2017

Parallel Programming CS : Dr Samir



Resources:

Compress Image File Formats:
Addison-Wesley
Author: John Miano ACM Press 1999

PNG: The Definitive Guilde
O’Reilly (The Mouse Book)
Greg Roelofs June 1999

C++ Concurrency In Action
Manning Publications
Author: Anthony Williams 2012

libpng http://libpng.org/
libpng is the official PNG reference library. It supports almost all PNG features, is extensible, and has been extensively tested for over 20 years. The home site for development versions (i.e., may be buggy or subject to change or include experimental features) is http://libpng.sourceforge.net/, and the place to go for questions about the library is the png-mng-implement mailing list.

Zlib compression http://www.zlib.net/
A Massively Spiffy Yet Delicately Unobtrusive Compression Library
(Also Free, Not to Mention Unencumbered by Patents) (Not Related to the Linux zlibc Compressing File-I/O Library)
Web pages originally created by Greg Roelofs and maintained by Mark Adler. If this page seems suspiciously similar to the PNG Home Page, rest assured that the similarity is completely coincidental. No, really.
zlib was written by Jean-loup Gailly (compression) and Mark Adler (decompression).
Current release: zlib 1.2.8 April 28, 2013





PNG File Format: Constructed by “Chunks” which have data embedded within them.

All PNG files begin with a PNG signature that can also act as a check some for some common transport protocol errors.

PNG Header is always 8 bytes in
one byte chars the sequence is as follows:
211 P N G \r \n 032 \n

in one byte Octal:
211 120 116 107 015 012 032 012

Decimal Bytes
137 80 78 71 13 10 26 10

These bytes can be read off by a program and stored, or ignored. They have no impact on the practical decoding of the PNG file, other than one might want to check them against the standard to ensure the integrity of PNG’s file transmition.


After the header, chunks make of the rest of the file. Each chunk has the following format:


Length

4 Bytes in big endian format

Type

4 bytes

Data

0 - 2,147,483,647 bytes as defined in the Length field

CRC

4 byte


Interpreting the chunks makes for the majority of the workload for programs to read and right. The second field is the TYPE field. The PNG specification has a long list of publicly defined TYPES although private data types as allowed for application developers.



TYPE Field:

The type field has 4 bytes which are associated with ASCII representations and are case sensitive. In general this is not a string, although a code can use this data as strings to make comparisons if they chose. Note, however, that there is no ending NULL and the data is Big Endian.



The Byte array distinguishes interpretation rules based on the capitalization of the individual bytes of the array (which can be quickly checked with a bit check of the 5th bit) The rules are detailed in the following chart

5th Bit (Capitalization) Interpretation of Chunk Types

Byte 0

Critical

Is the byte critical for PNG interpretation

Byte 1

Public

Publicly Defined in the PNG Specification

Byte 2

Reserved

Must be always capitalized

Byte 3

Safe to Copy

Copy uninterpreted data if capitalized

PNG Files has a minimum scaffolding that is necessary for a valid file.

PNG Header

IHDR Chunk – Header Information embedded in data field

IDAT Chunk – Actual Data that has to be decompressed and decoded

IEND – The End – you can check for this in order to stop



A common layout of the file might be like this:



PNG Signature

IHDR Chunk

PLTE Chuck <== Must come prior to the first IDAT header and there can only be one

IDAT … and repeated in serial to include all the image raw data

IEND



CRC is a check some which can be looked up in independent sources. Data is compressed with the zlib compression. It was developed to be a patent free, free software implementation for compression after several lawsuits over compression algorithms shocked the software word in the mid-1990’s. It is maintained by a cadres of free software developers for nearly 20 years and while there are opportunities for threading and parallel coding within the compression algorithm, its a huge detour from the core of this project and it is advised to use the standard zlib library deflate() for such decompression. I did want to say a word about its design. It works by sampling a window of a stream of data, and using that window for replacement words on the data incoming to the stream.



If you have a stream of bytes such as this with a window of 16 bytes



a a b b c c d d e e a a c d h h I I j j



the positions 11 and 12 can be replaced with data from 1-2 and position 13 and 14 (cd) can be replaced 7,8. The window then shifts with the stream.

a a b b c c d d e e % & h h I I j j



This gives flexibility in data streaming within the compression and allows for some threading since we can pick up the compression in the middle of the file.



Data Chunks and threading



A better location for parallel coding is within the IDAT headers themselves, since they are already divided into chunks of length as defined in the first 4 bytes of a chunk. In order to do that, we need to first examine and dissect a PNG file. I wrote code to do just this. It includes a .h header file, a .cpp library, a main function file, and a make file. The main file look as follows:

 1 /*
 2  * =====================================================================================
 3  *
 4  *       Filename:  main_png.cpp
 5  *
 6  *    Description:  PNG Project - main
 7  *
 8  *        Version:  1.0
 9  *        Created:  11/30/2016 02:57:46 PM
10  *       Revision:  1.0
11  *       Compiler:  gcc
12  *
13  *         Author:  Ruben Safir (mn), ruben@mrbrklyn.com
14  *        Company:  NYLXS Inc
15  *
16  * =====================================================================================
17  */
18 #include <iostream>
19 #include "png_proj.h"
20 
21 int main(int argc, char **argv)
22 {
23 // const char * image_file_path = nullptr;
24    const char * image_file_path = "/home/ruben/images/tzfat/tzfat_dawn_blended_fused.png";
25    //const char * image_file_path = "/home/ruben/photo_album/images/135-red_sea_1.png";
26    png_proj::Image pngtestfile{image_file_path};
27 // pngtestfile.read_png();
28    std::cout << "MAIN: line:" << __LINE__ << " char * image size==>" << sizeof(image_file_path) << std::endl;
29    pngtestfile.read_header();
30    pngtestfile.read_chunk();
31    while(pngtestfile.getNext() < pngtestfile.get_end() ){
32       std::cout << "Hey  I am not Kosher Bird, yoy can't eat me!!"  << std::endl;
33    }
34 
35    return EXIT_SUCCESS;
36 }

The image is picked up and absorbed in RAM in whole



The header file, png_proj.h is as follows



  1 /*
  2  * =====================================================================================
  3  *
  4  *       Filename:  png_proj.h
  5  *
  6  *    Description:  png_proj.h
  7  *
  8  *        Version:  1.0
  9  *        Created:  11/30/2016 03:50:13 PM
 10  *       Revision:  none
 11  *       Compiler:  gcc
 12  *
 13  *         Author:  Ruben Safir (mn), ruben@mrbrklyn.com
 14  *        Company:  NYLXS Inc
 15  *
 16  * =====================================================================================
 17  */
 18 
 19 #ifndef PNGPRJ
 20 #define PNGPRJ
 21 #include <inttypes.h>
 22 #include <iostream>
 23 
 24 namespace png_proj{
 25    typedef uint32_t CHUNK;
 26    struct IHDR {
 27       int32_t width;
 28       int32_t height;
 29       int8_t depth;
 30       int8_t color_type; //0 greyscale, 2 RGB, 3 Palette, 4 greyscale with alpha, 6 RGB with alpha
 31       int8_t compress; //must be 0
 32       int8_t filter; // must be zero
 33       int8_t interlace;
 34    };
 35 
 36    /*
 37     * =====================================================================================
 38     *        Class:  Image
 39     *  Description:  Basic Image Library for PNG and Parrallel Programming Class
 40     * =====================================================================================
 41     */
 42    class Image
 43    {
 44       public:
 45          /* ====================  LIFECYCLE     ======================================= */
 46          Image ();                             /* constructor */
 47          Image(const char *);
 48 
 49 
 50          /* ====================  ACCESSORS     ======================================= */
 51 
 52          /*
 53           *--------------------------------------------------------------------------------------
 54           *       Class:  Image
 55           *      Method:  get_index
 56           *--------------------------------------------------------------------------------------
 57           */
 58          char * get_index (  )
 59             {
 60                return index;
 61             }     /* -----  end of method Image::get_index  ----- */
 62 
 63          /*
 64           *--------------------------------------------------------------------------------------
 65           *       Class:  Image
 66           *      Method:  set_index
 67           *--------------------------------------------------------------------------------------
 68           */
 69          inline void set_index ( char * value )
 70             {
 71                index = value;
 72                return ;
 73             }     /* -----  end of method Image::set_index  ----- */
 74 
 75          /*
 76           *--------------------------------------------------------------------------------------
 77           *       Class:  Image
 78           *      Method:  get_pic
 79           *--------------------------------------------------------------------------------------
 80           */
 81          char * get_pic (  )
 82             {
 83                return pic;
 84             }     /* -----  end of method Image::get_pic  ----- */
 85 
 86          /*
 87           *--------------------------------------------------------------------------------------
 88           *       Class:  Image
 89           *      Method:  get_header
 90           *--------------------------------------------------------------------------------------
 91           */
 92          char* get_header()
 93             {
 94                return loc_header_cpy;
 95             }     /* -----  end of method Image::get_header  ----- */
 96 
 97          /*
 98           *--------------------------------------------------------------------------------------
 99           *       Class:  Image
100           *      Method:  set_header
101           *--------------------------------------------------------------------------------------
102           */
103          void set_header ()
104             {
105                char * start = loc_header_cpy;
106                //loc_header_cpy is an array int he constructor of 8 chars
107 //             char * value = get_pic();
108                std::cout << "setting the header array**" << std::endl;
109                std::cout << "**************************" << std::endl;
110                for(int i = 0; i<8; i++){
111                   std::cout << "setting the header" << *get_index() << std::endl;
112                   *start   = *get_index(); //this is a copy
113                   std::cout << "header set to =>>" << *start<< std::endl;
114                   next_index();
115                   start++;
116                }
117                return ;
118             }     /* -----  end of method Image::set_header  ----- */
119 
120 
121          /*
122           *--------------------------------------------------------------------------------------
123           *       Class:  Image
124           *      Method:  set_pic
125           *--------------------------------------------------------------------------------------
126           */
127          void set_pic ( char * value )
128             {
129                pic   = value;
130                return ;
131             }     /* -----  end of method Image::set_pic  ----- */
132 
133          /*
134           *--------------------------------------------------------------------------------------
135           *       Class:  Image
136           *      Method:  get_length
137           *--------------------------------------------------------------------------------------
138           */
139          long unsigned int get_length (  )
140             {
141                return length;
142             }     /* -----  end of method Image::get_length  ----- */
143 
144          /*
145           *--------------------------------------------------------------------------------------
146           *       Class:  Image
147           *      Method:  set_length
148           *--------------------------------------------------------------------------------------
149           */
150          long unsigned set_length ( long unsigned int value )
151             {
152                length   = value;
153                return value ;
154             }     /* -----  end of method Image::set_length  ----- */
155 
156          /*
157           *--------------------------------------------------------------------------------------
158           *       Class:  Image
159           *      Method:  get_type
160           *--------------------------------------------------------------------------------------
161           */
162          inline int32_t get_type (  )
163             {
164                return type;
165             }     /* -----  end of method Image::get_type  ----- */
166 
167          /*
168           *--------------------------------------------------------------------------------------
169           *       Class:  Image
170           *      Method:  set_type
171           *--------------------------------------------------------------------------------------
172           */
173          int32_t set_type ( int32_t value )
174             {
175                type  = value;
176                return value;
177             }     /* -----  end of method Image::set_type  ----- */
178 
179 
180          /*
181           *--------------------------------------------------------------------------------------
182           *       Class:  Image
183           *      Method:  get_data
184           *--------------------------------------------------------------------------------------
185           */
186          uint8_t * get_data (  )
187             {
188                return data;
189             }     /* -----  end of method Image::get_data  ----- */
190 
191          /*
192           *--------------------------------------------------------------------------------------
193           *       Class:  Image
194           *      Method:  set_data
195           *--------------------------------------------------------------------------------------
196           */
197          void  set_data ( uint8_t * value )
198             {
199                if(data != nullptr){
200                std::cout << __LINE__ << " We are deleting data" << std::endl;
201                   uint8_t * tmp = data;
202                   data = nullptr;
203                   delete[] tmp;
204                }
205 //             std::cout << __LINE__ << " Hello World" << std::endl;
206                std::cout << __LINE__ << " ASSINGING DATA FIELD TO OBJECT" << std::endl;
207                data  = value;//the size is determined in get_length()
208                return ;
209             }     /* -----  end of method Image::set_data  ----- */
210 
211          /*
212           *--------------------------------------------------------------------------------------
213           *       Class:  Image
214           *      Method:  get_crc
215           *--------------------------------------------------------------------------------------
216           */
217              int32_t get_crc (  )
218             {
219                return crc;
220             }     /* -----  end of method Image<T>::get_crc  ----- */
221 
222          /*
223           *--------------------------------------------------------------------------------------
224           *       Class:  Image
225           *      Method:  set_crc
226           *--------------------------------------------------------------------------------------
227           */
228             void set_crc ( int32_t value )
229             {
230                crc   = value;
231                return ;
232             }     /* -----  end of method Image<T>::set_crc  ----- */
233 
234             char * get_end(){
235                return end;
236             };
237             void set_end(char * value){
238                end = value;
239             }
240 
241 
242          /* ====================  MUTATORS      ======================================= */
243          void read_png( const char * in = nullptr );
244          void read_header();
245          void read_chunk();
246          void next_index(){
247             char * tmp = get_index();
248             set_index(++tmp);
249          };
250          void header(){
251             read_header();
252          };
253          const char * getNext( );
254 
255          /* ====================  OPERATORS     ======================================= */
256 
257          /* ====================  DATA MEMBERS  ======================================= */
258       protected:
259 
260       private:
261          char * pic;
262          char loc_header_cpy[8];
263          char * index;
264          char * end;
265          long unsigned int length;
266          uint8_t * data = nullptr;
267          int32_t type;
268          int32_t crc;
269    }; /* -----  end of class Image  ----- */
270 
271 
272 }
273 #endif



Here we can see the constructor opens the file, and loads it into memory, records the size of the file, which is used to end loops later (although one can search of IEND type chunks) and indexes is kept central to the object. For the proposes of the threading, this central indexing is a problem. Each thread will need to take an index and copy it in order to read the data chunks that it requires.



Other information that is stored and reported is chunk length, the CRC for the chunk currently being looked at (again this will need to be localized for the threading), and the header, which is image wide. The implementation of the library files is as follows from png_proj.cpp



1 /*

2 * =====================================================================================

3 *

4 * Filename: png_proj.cpp

5 *

6 * Description: PNG Project

7 *

8 * Version: 1.0

9 * Created: 11/15/2016 12:08:44 PM

10 * Revision: none

11 * Compiler: gcc

12 *

13 * Author: Ruben Safir (mn), ruben@mrbrklyn.com

14 * Company: NYLXS Inc

15 *

16 * =====================================================================================

17 */

18 #include <iostream>

19 #include <thread>

20 #include <zlib.h>

21 #include <iostream>

22 #include <map>

23 #include <string>

24 #include <chrono>

25 #include <thread>

26 #include <mutex>

27 #include <fstream>

28 #include <netinet/in.h>

29 #include "png_proj.h"

30

31 namespace png_proj{

32

33 Image::Image(const char * in)

34 {

35 if(in != nullptr)

36 {

37 this->read_png(in);

38 }

39 }

40

41 void Image::read_png( const char * in)

42 {

43 std::streampos size;

44 std::ifstream file;

45 char * image;

46 if(in == nullptr)

47 {

48 file.open("/home/ruben/png_project/airplane2.PNG", std::ios::in|std::ios::binary|std::ios::ate);

49

50 }else

51 {

52 file.open(in, std::ios::in|std::ios::binary|std::ios::ate);

53 }

54

55 if (file.is_open())

56 {

57 size = file.tellg();

58 image = new char [size];

59 file.seekg (0, std::ios::beg);

60 file.read (image, size);

61 file.close();

62

63 ¦ std::cout << std::endl << "the entire file content is in memory";

64 ¦ std::cout << std::endl << "File Size: " << size << std::endl ;

65 set_length(size);

66 set_index(image);//set the pic buffer index

67 ¦ set_pic(image); //store the pic buffer

68 set_end( get_index() + get_length() );

69 set_header(); //set the internal copy of the header

70 ¦}

71 else{

72 ¦std::cout << std::endl << "Unable to open file";

73 }

74 }

75

76 void Image::read_header()

77 {

78 std::cout << "OK lets read the header!!" << std::endl;

79 if(get_header() == nullptr)

80 {

81 std::cerr << "The header hasn't been initialized yet" << std::endl;

82 //this shouldn't be possible because it is defined as 8 char int in the const

83 //and then it is filled user set_header

84 return;

85 }

86 for(int i = 0;i<8;i++)

87 {

88 std::cout << "index: " << i << " value: " << *( get_header() + i ) << std::endl;

89 }

90 std::cout << std::endl << "done reading header" << std::endl << std::endl << std::endl;

91 }

92

93 void Image::read_chunk()

94 {

95 char * cur = get_index();

96 CHUNK * tmp = reinterpret_cast<CHUNK *>(cur);

97 std::cout << std::endl << "Size of initial Chunk " << sizeof(*tmp) << std::endl;

98 for(int j = 0; j<4; j++){

99 std::cout << std::endl << "==> Raw Chunk Number " << j << ":\tvalue of => " << *tmp << std::endl;

100 switch ( j ) {

101 case 0:

102 std::cout << "***LENGTH****" << std::endl;

103 set_length( ntohl( static_cast<uint32_t>(*tmp) ) );

104 std::cout << "Length value => " << get_length() << std::endl;

105 break;

106 case 1:

107 std::cout << "***TYPE****" << std::endl;

108 set_type(static_cast<int32_t>(*tmp));

109 break;

110 case 2:

111 {

112 std::cout << "***DATA****" << std::endl;

113 unsigned long int l = static_cast<unsigned long int>(get_length());

114 std::cout << "buffer size should be " << get_length() << std::endl;

115 uint8_t * buffer = new uint8_t[l];

116 uint8_t * curarry = reinterpret_cast<uint8_t *>(tmp);

117 std::cout << "buffer element size is " << sizeof(*buffer) << std::endl;

118 std::cout << "buffer size is " << l << std::endl;

119 for(unsigned int k = 0; k < l; k++){

120 std::cout << std::endl << "BYTE NUMBER " << k << std::endl << "********" << std::endl;

121 buffer[k] = curarry[k];

122 std::cout << "data " << buffer[k] << std::endl;

123 std::cout << "tmp " << curarry[k] << std::endl;

124 }

125 set_data(buffer);

126 //cur = ( reinterpret_cast<char*>(tmp) );

127 cur = cur + l;

128 set_index(cur);

129 }

130 break;

131 case 3:

132 std::cout << "***CRC****" << std::endl;

133 set_crc(static_cast<int32_t>(*tmp));

134 break;

135 default:

136 std::cout << "***NOMANDSLAND****" << std::endl;

137 break;

138 } /* ----- end switch ----- */

139

140 if(j != 2){

141 //char * tmp2 = reinterpret_cast<char *>(tmp); //reading each byte

142 std::cout << std::endl << "Out of switch \tSizeof Byte " << sizeof(*cur) << std::endl;

143 for(int i=0; i<4; i++){

144 std::cout << "Character " << i << "::" << std::endl << "\t" << *cur << std::endl;

145 std::cout << "Byte " << i << "::" << std::endl << "\t" << static_cast<unsigned long int>(*cur) << std::endl;

146 cur++;

147 }

148 std::cout<<std::endl;

149 std::cout<<std::endl;

150 //tmp++;

151 //cur = ( reinterpret_cast<char*>(tmp) );

152 set_index(cur);

153 }

154 }

155 set_index(cur);

156 }

157

158 /*

159 ¦*--------------------------------------------------------------------------------------

160 ¦* Class: Image

161 ¦* Method: getNext

162 ¦* Description: gets the next chunk and reads the data

163 ¦*--------------------------------------------------------------------------------------

164 ¦*/

165

166 ¦const char * Image::getNext ()

167 {

168 std::cout << std::endl << "getNext" << std::endl;

169 // next_index();

170 read_chunk();

171 const char *next = get_index();

172 return next;

173 } /* ----- end of method Image::getNext ----- */

174

175

176 }

177





The main action is within the switch. Since we have always for sections per chunk, we can defined needed behaviors for each segment. The length is first read and converted to the correct endian format (since it is an uint32_t type) and read.



The TYPE chunk is just read and reported.



The CRC is just stored for now since it doesn’t affect this project.



The data is then read according to the number of bytes in length from the first segment. This involves BYTE 2 in the loop



110 case 2:

111                {
112                   std::cout << "***DATA****" << std::endl;
113                   unsigned long int l = static_cast<unsigned long int>(get_length());
114                   std::cout << "buffer size should be " << get_length() << std::endl;
115                   uint8_t * buffer = new uint8_t[l];
116                   uint8_t * curarry = reinterpret_cast<uint8_t *>(tmp);
117                   std::cout << "buffer element size is " << sizeof(*buffer)  << std::endl;
118                   std::cout << "buffer size is " << l  << std::endl;
119                   for(unsigned int k = 0; k < l; k++){
120                      std::cout << std::endl << "BYTE NUMBER " << k << std::endl << "********" << std::endl;
121                      buffer[k] = curarry[k];
122                      std::cout << "data " << buffer[k]  << std::endl;
123                      std::cout << "tmp " << curarry[k]  << std::endl;
124                   }
125                   set_data(buffer);
126                   //cur = ( reinterpret_cast<char*>(tmp) );
127                   cur = cur + l;
128                   set_index(cur);
129                }
130                break;



You see here that we recast the data feed according to the type that is needed for our program. It is critical for this to be correct for the reading of data and for the pointer arithmetic to work correctly. This is the reason for my printing out the size of the values of the objects that the pointers are pointing to. It lets me visually see that our pointers are casted correctly.



The output gives us a good look at the main pieces that we are going to target for threading, that is the breakdown of the treads:



1

2 the entire file content is in memory

3 File Size: 19365631

4 setting the header array**

5 **************************

6 setting the header<89>

7 header set to =>><89>

8 setting the headerP

9 header set to =>>P

10 setting the headerN

11 header set to =>>N

12 setting the headerG

13 header set to =>>G

14 setting the header^M

15 header set to =>>^M

16 setting the header

17

18 header set to =>>

19

20 setting the header^Z

21 header set to =>>^Z

22 setting the header

23

24 header set to =>>

25

26 MAIN: line:28 char * image size==>8

27 OK lets read the header!!

28 index: 0 value: <89>

29 index: 1 value: P

30 index: 2 value: N

31 index: 3 value: G

32 index: 4 value: ^M

33 index: 5 value:

34

35 index: 6 value: ^Z

36 index: 7 value:

37

38

39 done reading header

40

41 40

41

42

43 Size of initial Chunk 4

44

45 ==> Raw Chunk Number 0: value of => 218103808

46 ***LENGTH****

47 Length value => 13

48

49 Out of switch Sizeof Byte 1

50 Character 0::

51 ^@

52 Byte 0::

53 0

54 Character 1::

55 ^@

56 Byte 1::

57 0

58 Character 2::

59 ^@

60 Byte 2::

61 0

62 Character 3::

63 ^M

64 Byte 3::

65 13

66

67

68

69 ==> Raw Chunk Number 1: value of => 218103808

70 ***TYPE****

71

72 Out of switch Sizeof Byte 1

73 Character 0::

74 I

75 Byte 0::

76 73

77 Character 1::

78 H

79 Byte 1::

80 72

81 Character 2::

82 D

83 Byte 2::

84 68

85 Character 3::

86 R

87 Byte 3::

88 82

89

90

91

92 ==> Raw Chunk Number 2: value of => 218103808

93 ***DATA****

94 buffer size should be 13

95 buffer element size is 1

96 buffer size is 13

97

98 BYTE NUMBER 0

99 ********

100 data ^@

101 tmp ^@

102

103 BYTE NUMBER 1

104 ********

105 data ^@

106 tmp ^@



and so on



158 BYTE NUMBER 12

159 ********

160 data ^@

161 tmp ^@

162 206 ASSINGING DATA FIELD TO OBJECT

163

164 ==> Raw Chunk Number 3: value of => 218103808

165 ***CRC****

166

167 Out of switch Sizeof Byte 1

168 Character 0::

169 <86>

170 Byte 0::

171 18446744073709551494

172 Character 1::

173 -

174 Byte 1::

175 45

176 Character 2::

177 <

178 Byte 2::

179 60

180 Character 3::

181 Þ

182 Byte 3::

183 18446744073709551582

184

185

186

187 getNext



After the CRC field, we have the whole header. The header data contains information about this file that we can use later (like the reported size of the file). But we skip this and then head straight for the inner part of the PNG graphics



the next chunk is of the non-critical type gama:

189 Size of initial Chunk 4

190

191 ==> Raw Chunk Number 0: value of => 67108864

192 ***LENGTH****

193 Length value => 4

194

195 Out of switch Sizeof Byte 1

196 Character 0::

197 ^@

198 Byte 0::

199 0

200 Character 1::

201 ^@

202 Byte 1::

203 0

204 Character 2::

205 ^@

206 Byte 2::

207 0

208 Character 3::

209 ^D

210 Byte 3::

211 4

212

213

214

215 ==> Raw Chunk Number 1: value of => 67108864

216 ***TYPE****

217

218 Out of switch Sizeof Byte 1

219 Character 0::

220 g

221 Byte 0::

222 103

223 Character 1::

224 A

225 Byte 1::

226 65

227 Character 2::

228 M

229 Byte 2::

230 77

231 Character 3::

232 A

233 Byte 3::

234 65



Moving on the next the non-critical public type bKGD



287

288 Hey I am not Kosher Bird, yoy can't eat me!!

289

290 getNext

291

292 Size of initial Chunk 4

293

294 ==> Raw Chunk Number 0: value of => 100663296

295 ***LENGTH****

296 Length value => 6

297

298 Out of switch Sizeof Byte 1

299 Character 0::

300 ^@

301 Byte 0::

302 0

303 Character 1::

304 ^@

305 Byte 1::

306 0

307 Character 2::

308 ^@

309 Byte 2::

310 0

311 Character 3::

312 ^F

313 Byte 3::

314 6

315

316

317

318 ==> Raw Chunk Number 1: value of => 100663296

319 ***TYPE****

320

321 Out of switch Sizeof Byte 1

322 Character 0::

323 b

324 Byte 0::

325 98

326 Character 1::

327 K

328 Byte 1::

329 75

330 Character 2::

331 G

332 Byte 2::

333 71

334 Character 3::

335 D

336 Byte 3::

337 68

338

339



then comes the critical chunk type PHYs – which I will also pretty much ignore for this project



401 Hey I am not Kosher Bird, yoy can't eat me!!

402

403 getNext

404

405 Size of initial Chunk 4

406

407 ==> Raw Chunk Number 0: value of => 150994944

408 ***LENGTH****

409 Length value => 9

410

411 Out of switch Sizeof Byte 1

412 Character 0::

413 ^@

414 Byte 0::

415 0

416 Character 1::

417 ^@

418 Byte 1::

419 0

420 Character 2::

421 ^@

422 Byte 2::

423 0

424 Character 3::

425

426 Byte 3::

427 9

428

429

430

431 ==> Raw Chunk Number 1: value of => 150994944

432 ***TYPE****

433

434 Out of switch Sizeof Byte 1

435 Character 0::

436 p

437 Byte 0::

438 112

439 Character 1::

440 H

441 Byte 1::

442 72

443 Character 2::

444 Y

445 Byte 2::

446 89

447 Character 3::

448 s

449 Byte 3::

450 115

451



and another one, which we will bypass to reach a time stamp chunk



529 Hey I am not Kosher Bird, yoy can't eat me!!

530

531 getNext

532

533 Size of initial Chunk 4

534

535 ==> Raw Chunk Number 0: value of => 117440512

536 ***LENGTH****

537 Length value => 7

538

539 Out of switch Sizeof Byte 1

540 Character 0::

541 ^@

542 Byte 0::

543 0

544 Character 1::

545 ^@

546 Byte 1::

547 0

548 Character 2::

549 ^@

550 Byte 2::

551 0

552 Character 3::

553 ^G

554 Byte 3::

555 7

556

557

558

559 ==> Raw Chunk Number 1: value of => 117440512

560 ***TYPE****

561

562 Out of switch Sizeof Byte 1

563 Character 0::

564 t

565 Byte 0::

566 116

567 Character 1::

568 I

569 Byte 1::

570 73

571 Character 2::

572 M

573 Byte 2::

574 77

575 Character 3::

576 E

577 Byte 3::

578 69

579



until we finally reach the array of IDAT chunks which have lengths of 8192 bytes each



651 Size of initial Chunk 4

652

653 ==> Raw Chunk Number 0: value of => 2097152

654 ***LENGTH****

655 Length value => 8192

656

657 Out of switch Sizeof Byte 1

658 Character 0::

659 ^@

660 Byte 0::

661 0

662 Character 1::

663 ^@

664 Byte 1::

665 0

666 Character 2::

667

668 Byte 2::

669 32

670 Character 3::

671 ^@

672 Byte 3::

673 0

674

675

676

677 ==> Raw Chunk Number 1: value of => 2097152

678 ***TYPE****

679

680 Out of switch Sizeof Byte 1

681 Character 0::

682 I

683 Byte 0::

684 73

685 Character 1::

686 D

687 Byte 1::

688 68

689 Character 2::

690 A

691 Byte 2::

692 65

693 Character 3::

694 T

695 Byte 3::

696 84

697

698

699

700 ==> Raw Chunk Number 2: value of => 2097152

701 ***DATA****

702 buffer size should be 8192

703 buffer element size is 1

704 buffer size is 8192

705

706 BYTE NUMBER 0

707 ********

708 data ^@

709 tmp ^@

710

711 BYTE NUMBER 1

712 ********

713 data ^@

714 tmp ^@

715

41737 BYTE NUMBER 8191

41738 ********

41739 data ÿ

41740 tmp ÿ

41741 200 We are deleting data

41742 206 ASSINGING DATA FIELD TO OBJECT

41743

41744 ==> Raw Chunk Number 3: value of => 2097152

41745 ***CRC****

41746

41747 Out of switch Sizeof Byte 1

41748 Character 0::

41749 <8c>

41750 Byte 0::

41751 18446744073709551500

41752 Character 1::

41753 s

41754 Byte 1::

41755 115

41756 Character 2::

41757 ^Q

41758 Byte 2::

41759 17

41760 Character 3::

41761 ­

41762 Byte 3::

41763 18446744073709551533

41764

41765



and so on through the rest of the file until we reach the end





41766 Hey I am not Kosher Bird, yoy can't eat me!!

41767

41768 getNext

41769

41770 Size of initial Chunk 4

41771

41772 ==> Raw Chunk Number 0: value of => 2097152

41773 ***LENGTH****

41774 Length value => 8192

41775

41776 Out of switch Sizeof Byte 1

41777 Character 0::

41778 ^@

41779 Byte 0::

41780 0

41781 Character 1::

41782 ^@

41783 Byte 1::

41784 0

41785 Character 2::

41786

41787 Byte 2::

41788 32

41789 Character 3::

41790 ^@

41791 Byte 3::

41792 0

41793

41794

41795

41796 ==> Raw Chunk Number 1: value of => 2097152

41797 ***TYPE****

41798

41799 Out of switch Sizeof Byte 1

41800 Character 0::

41801 I

41802 Byte 0::

41803 73

41804 Character 1::

41805 D

41806 Byte 1::

41807 68

41808 Character 2::

41809 A

41810 Byte 2::

41811 65

41812 Character 3::

41813 T

41814 Byte 3::

41815 84

41816

41817

41818

41819 ==> Raw Chunk Number 2: value of => 2097152

41820 ***DATA****

41821 buffer size should be 8192

41822 buffer element size is 1

41823 buffer size is 8192

41824

41825 BYTE NUMBER 0

41826 ********

41827 data ^@

41828 tmp ^@

41829

41830 BYTE NUMBER 1

41831 ********

41832 data ^@

41833 tmp ^@

41834



and on



97028124 Hey I am not Kosher Bird, yoy can't eat me!!

97028125

97028126 getNext

97028127

97028128 Size of initial Chunk 4

97028129

97028130 ==> Raw Chunk Number 0: value of => 0

97028131 ***LENGTH****

97028132 Length value => 0

97028133

97028134 Out of switch Sizeof Byte 1

97028135 Character 0::

97028136 ^@

97028137 Byte 0::

97028138 0

97028139 Character 1::

97028140 ^@

97028141 Byte 1::

97028142 0

97028143 Character 2::

97028144 ^@

97028145 Byte 2::

97028146 0

97028147 Character 3::

97028148 ^@

97028149 Byte 3::

97028150 0

97028151

97028152

97028153

97028154 ==> Raw Chunk Number 1: value of => 0

97028155 ***TYPE****

97028156

97028157 Out of switch Sizeof Byte 1

97028158 Character 0::

97028159 I

97028160 Byte 0::

97028161 73

97028162 Character 1::

97028163 E

97028164 Byte 1::

97028165 69

97028166 Character 2::

97028167 N

97028168 Byte 2::

97028169 78

97028170 Character 3::

97028171 D

97028172 Byte 3::

97028173 68

97028174

97028175

97028176

97028177 ==> Raw Chunk Number 2: value of => 0

97028178 ***DATA****

97028179 buffer size should be 0

97028180 buffer element size is 1

97028181 buffer size is 0

97028182 200 We are deleting data

97028183 206 ASSINGING DATA FIELD TO OBJECT

97028184

97028185 ==> Raw Chunk Number 3: value of => 0

97028186 ***CRC****

97028187

97028188 Out of switch Sizeof Byte 1

97028189 Character 0::

97028190 ®

97028191 Byte 0::

97028192 18446744073709551534

97028193 Character 1::

97028194 B

97028195 Byte 1::

97028196 66

97028197 Character 2::

97028198 `

97028199 Byte 2::

97028200 96

97028201 Character 3::

97028202 <82>

97028203 Byte 3::

97028204 18446744073709551490

97028205

97028206



DONE



Clearly, we have an opportunity to parallize the chunk reading. What are the factors that we need to account for when we paralize the attach on reading the PNG file





A) File Location Tracking

Each chunk is in order and as we separate the processing from the order then we will need to reassemble the pieces in order to maintain a coherent image.



B) Localization of indexing

Indexing is currently being done on the object level. While that still needs to happen so that chunks can be parsed out correctly, the byte size indexing through the data needs to be localized to the chunk. This is likely best done in C++ by leveraging encapsulation by making

new chunk type objects which have their own indexes and which are called by threads.

C) Localization of Data

Currently chunk data is stored in the image object. When a chunks data is aquired, the old data is deleted off the heap and the new data is passed to the object. We will need the data to remain intact with the new chunk object until it is assembled in the image object to its destination, may that be a file or to a GPU.

D) Decompression moved to Chunks



E) setting an optimal number of threads.





This is all that I wanted for this project, but other opportunities are available for parallelization



A) PNG can be hooked directly into opengl and cuda. In fact, such hooks are build into libpng

B) Compression itself can be done parallel if the size of a chunk is large enough to justify it.

C) Geometric design can be added along with interlacing. By physically dividing the image into subdividing blocks, recursion can be applied and binary trees can be applied to it. This is especially true when creating PNG files.