This is the Deflater class. The deflater class compresses input with the deflate algorithm described in RFC 1951. It has several compression levels and three different strategies described below. This class is not thread safe. This is inherent in the API, due to the split of deflate and setInput. author of the original java version : Jochen Hoenicke
		/// <summary>
		/// Creates a new DeflaterOutputStream with the given Deflater and
		/// buffer size.
		/// </summary>
		/// <param name="baseOutputStream">
		/// The output stream where deflated output is written.
		/// </param>
		/// <param name="deflater">
		/// The underlying deflater to use
		/// </param>
		/// <param name="bufferSize">
		/// The buffer size to use when deflating
		/// </param>
		/// <exception cref="ArgumentOutOfRangeException">
		/// bufsize is less than or equal to zero.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// baseOutputStream does not support writing
		/// </exception>
		/// <exception cref="ArgumentNullException">
		/// deflater instance is null
		/// </exception>
		public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater, int bufferSize) {
			if (baseOutputStream == null) {
				throw new ArgumentNullException("baseOutputStream");
			}

			if (baseOutputStream.CanWrite == false) {
				throw new ArgumentException("Must support writing", "baseOutputStream");
			}

			if (deflater == null) {
				throw new ArgumentNullException("deflater");
			}

			if (bufferSize <= 0) {
				throw new ArgumentOutOfRangeException("bufferSize");
			}

			baseOutputStream_ = baseOutputStream;
			buffer_ = new byte[bufferSize];
			deflater_ = deflater;
		}
		/// <summary>
		/// Creates a new DeflaterOutputStream with the given Deflater and
		/// default buffer size.
		/// </summary>
		/// <param name="baseOutputStream">
		/// the output stream where deflated output should be written.
		/// </param>
		/// <param name="deflater">
		/// the underlying deflater.
		/// </param>
		public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater)
			: this(baseOutputStream, deflater, 512) {
		}
        /**
         * Write the image data into the pngBytes array.
         * This will write one or more PNG "IDAT" chunks. In order
         * to conserve memory, this method grabs as many rows as will
         * fit into 32K bytes, or the whole image; whichever is less.
         *
         *
         * @return true if no errors; false if error grabbing pixels
         */
        protected bool WriteImageData()
        {
            int rowsLeft = height;  // number of rows remaining to write
            int startRow = 0;       // starting row to process this time through
            int nRows;              // how many rows to grab at a time

            byte[] scanLines;       // the scan lines to be compressed
            int scanPos;            // where we are in the scan lines
            int startPos;           // where this line's actual pixels start (used for filtering)

            byte[] compressedLines; // the resultant compressed lines
            int nCompressed;        // how big is the compressed area?

            //int depth;              // color depth ( handle only 8 or 32 )

            bytesPerPixel = (encodeAlpha) ? 4 : 3;

            Deflater scrunch = new Deflater(compressionLevel);
            MemoryStream outBytes = new MemoryStream(1024);

            DeflaterOutputStream compBytes = new DeflaterOutputStream(outBytes, scrunch);
            try {
                while (rowsLeft > 0) {
                    nRows = Math.Min(32767 / (width * (bytesPerPixel + 1)), rowsLeft);
                    nRows = Math.Max(nRows, 1);

                    int[] pixels = new int[width * nRows];
                    Array.Copy(this.pixelData, width * startRow, pixels, 0, width * nRows);

                    /*
                     * Create a data chunk. scanLines adds "nRows" for
                     * the filter bytes.
                     */
                    scanLines = new byte[width * nRows * bytesPerPixel + nRows];

                    if (filter == FILTER_SUB) {
                        leftBytes = new byte[16];
                    }
                    if (filter == FILTER_UP) {
                        priorRow = new byte[width * bytesPerPixel];
                    }

                    scanPos = 0;
                    startPos = 1;
                    for (int i = 0; i < width * nRows; i++) {
                        if (i % width == 0) {
                            scanLines[scanPos++] = (byte) filter;
                            startPos = scanPos;
                        }
                        scanLines[scanPos++] = (byte) ((pixels[i] >> 16) & 0xff);
                        scanLines[scanPos++] = (byte) ((pixels[i] >> 8) & 0xff);
                        scanLines[scanPos++] = (byte) ((pixels[i]) & 0xff);
                        if (encodeAlpha) {
                            scanLines[scanPos++] = (byte) ((pixels[i] >> 24) & 0xff);
                        }
                        if ((i % width == width - 1) && (filter != FILTER_NONE)) {
                            if (filter == FILTER_SUB) {
                                FilterSub(scanLines, startPos, width);
                            }
                            if (filter == FILTER_UP) {
                                FilterUp(scanLines, startPos, width);
                            }
                        }
                    }

                    /*
                     * Write these lines to the output area
                     */
                    compBytes.Write(scanLines, 0, scanPos);

                    startRow += nRows;
                    rowsLeft -= nRows;
                }
                compBytes.Close();

                /*
                 * Write the compressed bytes
                 */
                compressedLines = outBytes.ToArray();
                nCompressed = compressedLines.Length;

                crc.Reset();
                bytePos = WriteInt4(nCompressed, bytePos);
                bytePos = WriteBytes(IDAT, bytePos);
                crc.Update(IDAT);
                bytePos = WriteBytes(compressedLines, nCompressed, bytePos);
                crc.Update(compressedLines, 0, nCompressed);

                crcValue = crc.Value;
                bytePos = WriteInt4((int) crcValue, bytePos);
                scrunch.Finish();
                return true;
            } catch {
                return false;
            }
        }
 /// <summary>
 /// Creates a new DeflaterOutputStream with the given Deflater and
 /// default buffer size.
 /// </summary>
 /// <param name="baseOutputStream">
 /// the output stream where deflated output should be written.
 /// </param>
 /// <param name="deflater">
 /// the underlying deflater.
 /// </param>
 public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater)
     : this(baseOutputStream, deflater, 512)
 {
 }
        /**
         * Write the image data into the pngBytes array.
         * This will write one or more PNG "IDAT" chunks. In order
         * to conserve memory, this method grabs as many rows as will
         * fit into 32K bytes, or the whole image; whichever is less.
         *
         *
         * @return true if no errors; false if error grabbing pixels
         */
        protected bool WriteImageData()
        {
            int rowsLeft = height;              // number of rows remaining to write
            int startRow = 0;                   // starting row to process this time through
            int nRows;                          // how many rows to grab at a time

            byte[] scanLines;                   // the scan lines to be compressed
            int    scanPos;                     // where we are in the scan lines
            int    startPos;                    // where this line's actual pixels start (used for filtering)

            byte[] compressedLines;             // the resultant compressed lines
            int    nCompressed;                 // how big is the compressed area?

            //int depth;              // color depth ( handle only 8 or 32 )

            bytesPerPixel = (encodeAlpha) ? 4 : 3;

            Deflater     scrunch  = new Deflater(compressionLevel);
            MemoryStream outBytes = new MemoryStream(1024);

            DeflaterOutputStream compBytes = new DeflaterOutputStream(outBytes, scrunch);

            try {
                while (rowsLeft > 0)
                {
                    nRows = Math.Min(32767 / (width * (bytesPerPixel + 1)), rowsLeft);
                    nRows = Math.Max(nRows, 1);

                    int[] pixels = new int[width * nRows];
                    Array.Copy(this.pixelData, width * startRow, pixels, 0, width * nRows);

                    /*
                     * Create a data chunk. scanLines adds "nRows" for
                     * the filter bytes.
                     */
                    scanLines = new byte[width * nRows * bytesPerPixel + nRows];

                    if (filter == FILTER_SUB)
                    {
                        leftBytes = new byte[16];
                    }
                    if (filter == FILTER_UP)
                    {
                        priorRow = new byte[width * bytesPerPixel];
                    }

                    scanPos  = 0;
                    startPos = 1;
                    for (int i = 0; i < width * nRows; i++)
                    {
                        if (i % width == 0)
                        {
                            scanLines[scanPos++] = (byte)filter;
                            startPos             = scanPos;
                        }
                        scanLines[scanPos++] = (byte)((pixels[i] >> 16) & 0xff);
                        scanLines[scanPos++] = (byte)((pixels[i] >> 8) & 0xff);
                        scanLines[scanPos++] = (byte)((pixels[i]) & 0xff);
                        if (encodeAlpha)
                        {
                            scanLines[scanPos++] = (byte)((pixels[i] >> 24) & 0xff);
                        }
                        if ((i % width == width - 1) && (filter != FILTER_NONE))
                        {
                            if (filter == FILTER_SUB)
                            {
                                FilterSub(scanLines, startPos, width);
                            }
                            if (filter == FILTER_UP)
                            {
                                FilterUp(scanLines, startPos, width);
                            }
                        }
                    }

                    /*
                     * Write these lines to the output area
                     */
                    compBytes.Write(scanLines, 0, scanPos);

                    startRow += nRows;
                    rowsLeft -= nRows;
                }
                compBytes.Close();

                /*
                 * Write the compressed bytes
                 */
                compressedLines = outBytes.ToArray();
                nCompressed     = compressedLines.Length;

                crc.Reset();
                bytePos = WriteInt4(nCompressed, bytePos);
                bytePos = WriteBytes(IDAT, bytePos);
                crc.Update(IDAT);
                bytePos = WriteBytes(compressedLines, nCompressed, bytePos);
                crc.Update(compressedLines, 0, nCompressed);

                crcValue = crc.Value;
                bytePos  = WriteInt4((int)crcValue, bytePos);
                scrunch.Finish();
                return(true);
            } catch {
                return(false);
            }
        }