// write a compressed text chunk
		void png_write_zTXt(string key, string text, PNG_TEXT_COMPRESSION compression)
		{
			uint key_len;
			byte[] new_key=null;

			if((key_len=png_check_keyword(key, ref new_key))==0) return;

			if(text==null||text.Length==0||compression==PNG_TEXT_COMPRESSION.NONE)
			{
				png_write_tEXt(key, text);
				return;
			}

			compression_state comp;
			comp.output_ptr=null;
			comp.input=null;

			// compute the compressed data; do it now for the length
			uint text_len=png_text_compress(Encoding.ASCII.GetBytes(text), compression, ref comp);

			// write start of chunk
			png_write_chunk_start(PNG.zTXt, key_len+text_len+2);
			new_key[key_len+1]=(byte)compression;
			// write key and compression
			png_write_chunk_data(new_key, key_len+2);
			// write the compressed data
			png_write_compressed_data_out(ref comp);

			// close the chunk
			png_write_chunk_end();
		}
		// write an iTXt chunk
		void png_write_iTXt(PNG_TEXT_COMPRESSION compression, string key, string lang, string lang_key, string text)
		{
			uint lang_len, key_len;
			byte[] new_lang=null, new_key=null;

			if((key_len=png_check_keyword(key, ref new_key))==0) return;

			if((lang_len=png_check_keyword(lang, ref new_lang))==0)
			{
				Debug.WriteLine("Empty language field in iTXt chunk");
				new_lang=null;
				lang_len=0;
			}

			uint lang_key_len=0;
			if(lang_key!=null) lang_key_len=(uint)lang_key.Length;

			uint text_len=0;
			if(text!=null) text_len=(uint)text.Length;

			compression_state comp;
			comp.output_ptr=null;
			comp.input=null;

			// compute the compressed data; do it now for the length
			text_len=png_text_compress(text_len==0?null:Encoding.UTF8.GetBytes(text), compression-2, ref comp);

			// make sure we include the compression flag, the compression byte,
			// and the NULs after the key, lang, and lang_key parts
			png_write_chunk_start(PNG.iTXt, 5+key_len+lang_len+lang_key_len+text_len); // 5: comp byte, comp flag, terminators for key, lang and lang_key

			// We leave it to the application to meet PNG-1.0 requirements on the
			// contents of the text. PNG-1.0 through PNG-1.2 discourage the use of
			// any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them.
			// The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
			png_write_chunk_data(new_key, key_len+1);

			byte[] cbuf=new byte[2];

			// set the compression flag
			if(compression==PNG_TEXT_COMPRESSION.ITXT_COMPRESSION_NONE||compression==PNG_TEXT_COMPRESSION.NONE) cbuf[0]=0;
			else cbuf[0]=1; // compression==PNG_TEXT_COMPRESSION.ITXT_COMPRESSION_zTXt

			// set the compression method
			cbuf[1]=0;
			png_write_chunk_data(cbuf, 2);

			cbuf[0]=0;
			png_write_chunk_data((new_lang!=null?new_lang:cbuf), lang_len+1);
			png_write_chunk_data((lang_key!=null?Encoding.UTF8.GetBytes(lang_key):cbuf), lang_key_len+1);
			png_write_compressed_data_out(ref comp);

			png_write_chunk_end();
		}
		// 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;
		}