title: Writing a PNG using zlib
body: <p>I am trying to write a PNG using zlib directly. However, the output file is not correct. Looking at it in frhed, the IDAT chunk shows periodic patterns and a large block of zeros. This indicates that something is wrong when calling zlib. Here's the code:</p>
  
  <pre><code>#include "FrameGrabber.h"
  #include "Image.h"
  #include "crc.h"
  #include &lt;zlib.h&gt;
  #include &lt;stdint.h&gt;
  
  #include &lt;cstdio&gt;
  #include &lt;cassert&gt;
  
  
  
  template&lt;class T&gt;
  void assign(void* addr,T x)
  {
  T* p_out= (T*)addr ;
  *p_out=x;
  }
  
  inline int32_t swap_bytes(int32_t x)
  {
  asm("bswap %1":"=r"(x):"r"(x):);
  return x;
  }
  
  //Input is BGRx (convert to BGR (should be swapped to RGB later) and add a byte in the beginning)
  void filterApply(const unsigned char* const* scanlines,char* buffer_png,int width,int height)
  {
  for(int k=0;k&lt;height;++k)
      {
      *buffer_png=0;
      ++buffer_png;
      for(int l=0;l&lt;width;++l)
          {
          assign(buffer_png,( (int32_t*)(scanlines[k])  )[l] );
          buffer_png+=3;
          }
      }
  }
  
  size_t compress(const char* buffer_uncompressed,char* buffer_compressed,size_t length_in)
  {
  z_stream stream;
  memset(&amp;stream,0,sizeof(stream));
  //  15 bits=32K?
  deflateInit2(&amp;stream,6,Z_DEFLATED,15,9,Z_FILTERED);
  
  stream.avail_in=length_in;
  stream.next_in=(unsigned char*)buffer_uncompressed;
  stream.avail_out=length_in;
  stream.next_out =(unsigned char*)buffer_compressed;
  do
      {       
      deflate(&amp;stream, Z_FINISH);
      }
  while (stream.avail_out == 0);
  deflateEnd(&amp;stream);
  return stream.total_out;
  }
  
  
  
  const size_t CHUNK_BASE_SIZE=12;
  
  void Chunk_sizeSet(char* chunk,uint32_t size)
  {assign(chunk,swap_bytes(size));}
  
  void Chunk_IDSet(char* chunk,uint32_t id)
  {assign(chunk+4,swap_bytes(id));}
  
  void Chunk_CRCSet(char* chunk,const PngCRC&amp; crc,uint32_t size_chunk_data)
  {assign(chunk+8+size_chunk_data, swap_bytes(crc(chunk+4,size_chunk_data+4)) );}
  
  
  
  const size_t IHDR_SIZE=13;
  const int IHDR_COLORTYPE_RGB=2;
  
  void IHDR_widthSet(char* chunk,int32_t width)
  {assign(chunk+8,swap_bytes(width));}
  
  void IHDR_heightSet(char* chunk,int32_t height)
  {assign(chunk+12,swap_bytes(height));}
  
  void IHDR_bitDepthSet(char* chunk,char bd)
  {chunk[16]=bd;}
  
  void IHDR_colorTypeSet(char* chunk,char ct)
  {chunk[17]=ct;}
  
  void IHDR_compressionMethodSet(char* chunk,char cmprm)
  {chunk[18]=cmprm;}
  
  void IHDR_filterMethodSet(char* chunk,char filter)
  {chunk[19]=filter;}
  
  void IHDR_interlaceMethodSet(char* chunk,char interlace)
  {chunk[20]=interlace;}
  
  
  
  int main()
  {
  PngCRC crc;                              //The CRC code works
  char signature[8]={137,80,78,71,13,10,26,10};
  
  char IEND[CHUNK_BASE_SIZE];
  Chunk_sizeSet(IEND,0);
  Chunk_IDSet(IEND,0x49454e44);
  Chunk_CRCSet(IEND,crc,0);
  
  FrameGrabber grabber(GetDesktopWindow()); //Grab the desktop (works)
  Image img(grabber);
  grabber.grab();
  
  char IHDR[CHUNK_BASE_SIZE+IHDR_SIZE];
  Chunk_sizeSet(IHDR,CHUNK_BASE_SIZE+IHDR_SIZE);
  Chunk_IDSet(IHDR,0x49484452);
  IHDR_widthSet(IHDR,grabber.widthGet());
  IHDR_heightSet(IHDR,grabber.heightGet());
  IHDR_bitDepthSet(IHDR,8);
  IHDR_colorTypeSet(IHDR,IHDR_COLORTYPE_RGB);
  IHDR_compressionMethodSet(IHDR,0);
  IHDR_filterMethodSet(IHDR,0);
  IHDR_interlaceMethodSet(IHDR,0);
  Chunk_CRCSet(IHDR,crc,IHDR_SIZE);   
  
  
  size_t size_uncompressed=(1+3*grabber.widthGet())*grabber.heightGet();
  char* img_png_uncompressed=(char*)malloc(size_uncompressed);
  filterApply(img.rowsGet(),img_png_uncompressed,grabber.widthGet(),grabber.heightGet());
  
      //The compressed chunk should not be larger than the uncompressed one.
  char* IDAT=(char*)malloc(size_uncompressed+CHUNK_BASE_SIZE);
  
  int32_t size_idat=compress(img_png_uncompressed,IDAT+CHUNK_BASE_SIZE,size_uncompressed);
  Chunk_sizeSet(IDAT,size_idat);
  Chunk_IDSet(IDAT,0x49444154);
  Chunk_CRCSet(IDAT,crc,size_idat);
  
  
  FILE* file_out=fopen("test.png","wb");
  
  fwrite(signature,1,sizeof(signature),file_out);
  fwrite(IHDR,1,sizeof(IHDR),file_out);
  fwrite(IDAT,1,size_idat,file_out);
  fwrite(IEND,1,sizeof(IEND),file_out);
  free(IDAT);
  fclose(file_out);
  
  return 0;
  }
  </code></pre>
  
  <p>EDIT: Found a bug in filterApply. Now i do not get any large empty blocks but the file is still invalid. It just affects input data so it is correct.</p>