// ship the compressed text out via chunk writes void png_write_compressed_data_out(ref compression_state comp) { // handle the no-compression case if(comp.input!=null) { png_write_chunk_data(comp.input, (uint)comp.input.Length); return; } // write saved output buffers, if any for(int i=0; i<comp.output_ptr.Count; i++) { png_write_chunk_data(comp.output_ptr[i], zbuf_size); } if(comp.output_ptr!=null) comp.output_ptr.Clear(); // write anything left in zbuf if(zstream.avail_out<zbuf_size) png_write_chunk_data(zbuf, zbuf_size-zstream.avail_out); // reset zlib for another zTXt/iTXt or image data zlib.deflateReset(zstream); }
// compress given text into storage in the png_ptr structure uint png_text_compress(byte[] text, PNG_TEXT_COMPRESSION compression, ref compression_state comp) { comp.input=null; comp.output_ptr=null; // we may just want to pass the text right through if(compression==PNG_TEXT_COMPRESSION.NONE) { comp.input=text; return (uint)text.Length; } if(compression>=PNG_TEXT_COMPRESSION.LAST) Debug.WriteLine("Unknown compression type "+(int)compression); // We can't write the chunk until we find out how much data we have, // which means we need to run the compressor first and save the // output. This shouldn't be a problem, as the vast majority of // comments should be reasonable, but we will set up an array of // malloc'd pointers to be sure. // // If we knew the application was well behaved, we could simplify this // greatly by assuming we can always malloc an output buffer large // enough to hold the compressed text ((1001*text_len/1000)+12) // and malloc this directly. The only time this would be a bad idea is // if we can't malloc more than 64K and we have 64K of random input // data, or if the input string is incredibly large (although this // wouldn't cause a failure, just a slowdown due to swapping). // set up the compression buffers zstream.avail_in=(uint)text.Length; zstream.next_in=0; zstream.in_buf=text; zstream.avail_out=zbuf_size; zstream.next_out=0; zstream.out_buf=zbuf; comp.output_ptr=new List<byte[]>(); // this is the same compression loop as in png_write_row() int ret; do { // compress the data ret=zlib.deflate(zstream, zlib.Z_NO_FLUSH); if(ret!=zlib.Z_OK) { // error if(zstream.msg!=null&&zstream.msg.Length>0) throw new PNG_Exception(zstream.msg); throw new PNG_Exception("zlib error"); } // check to see if we need more room if(zstream.avail_out==0) { // save the data byte[] buf=new byte[zbuf_size]; zbuf.CopyTo(buf, 0); comp.output_ptr.Add(buf); // and reset the buffer zstream.avail_out=zbuf_size; zstream.next_out=0; zstream.out_buf=zbuf; } // continue until we don't have any more to compress } while(zstream.avail_in!=0); // finish the compression do { // tell zlib we are finished ret=zlib.deflate(zstream, zlib.Z_FINISH); if(ret!=zlib.Z_STREAM_END) { // we got an error if(zstream.msg!=null&&zstream.msg.Length>0) throw new PNG_Exception(zstream.msg); throw new PNG_Exception("zlib error"); } if(ret==zlib.Z_OK) { // check to see if we need more room if(zstream.avail_out==0) { // save off the data byte[] buf=new byte[zbuf_size]; zbuf.CopyTo(buf, 0); comp.output_ptr.Add(buf); // and reset the buffer pointers zstream.avail_out=zbuf_size; zstream.next_out=0; zstream.out_buf=zbuf; } } } while(ret!=zlib.Z_STREAM_END); // text length is number of buffers plus last buffer uint text_len=zbuf_size*(uint)comp.output_ptr.Count; if(zstream.avail_out<zbuf_size) text_len+=zbuf_size-zstream.avail_out; return text_len; }