public static void EncodeAsync(byte[] dataRgba, int stride, Action <Exception, byte[]> callback)
 {
     ThreadPool.QueueUserWorkItem((state) =>
     {
         try
         {
             byte[] png = PngEncoder.Encode(dataRgba, stride);
             callback(null, png);
         }
         catch (Exception ex)
         {
             callback(ex, null);
             throw;
         }
     }, null);
 }
Exemple #2
0
            private void EncodeCallback(object state)
            {
                byte[] byteData = this.NativeData.ToArray();
                int    downsampledStride;

                byteData = Downsampler.Downsample(byteData, this.Width * 4, this.MaximumWidth, this.MaximumHeight, out downsampledStride);
                if (this.Type == ScreenshotType.Png)
                {
                    byteData = PngEncoder.Encode(byteData, downsampledStride);
                }
                if (this.Callback != null)
                {
                    this.Callback(byteData, this.State);
                }
                this.NativeData.Dispose();
                this.IsInUse = false;
            }
        public static byte[] Encode(byte[] dataRgba, int stride)
        {
            // Preconditions
            if (dataRgba == null)
            {
                throw new ArgumentNullException("dataRgba");
            }

            if (dataRgba.Length == 0)
            {
                throw new ArgumentException("The data length must be greater than 0.");
            }

            if (stride == 0)
            {
                throw new ArgumentException("The stride must be greater than 0.");
            }

            if (stride % 4 != 0)
            {
                throw new ArgumentException("The stride must be evenly divisible by 4.");
            }

            if (dataRgba.Length % 4 != 0)
            {
                throw new ArgumentException("The data must be evenly divisible by 4.");
            }

            if (dataRgba.Length % stride != 0)
            {
                throw new ArgumentException("The data must be evenly divisible by the stride.");
            }

            // Dimensions
            int pixels = dataRgba.Length / 4;
            int width  = stride / 4;
            int height = pixels / width;

            // IHDR Chunk
            byte[] ihdrData     = new byte[13];
            int    ihdrPosition = 0;

            ihdrData.AppendInt(ref ihdrPosition, width);
            ihdrData.AppendInt(ref ihdrPosition, height);
            ihdrData.AppendByte(ref ihdrPosition, 8); // Bit depth
            ihdrData.AppendByte(ref ihdrPosition, 6); // Color type (color + alpha)
            ihdrData.AppendByte(ref ihdrPosition, 0); // Compression method (always 0)
            ihdrData.AppendByte(ref ihdrPosition, 0); // Filter method (always 0)
            ihdrData.AppendByte(ref ihdrPosition, 0); // Interlace method (no interlacing)

            // IDAT Chunk
            byte[] scanlineData         = new byte[dataRgba.Length + height];
            int    scanlineDataPosition = 0;
            int    scanlinePosition     = 0;

            for (int i = 0; i < dataRgba.Length; i++)
            {
                if (scanlinePosition >= stride)
                {
                    scanlinePosition = 0;
                }

                if (scanlinePosition == 0)
                {
                    scanlineData.AppendByte(ref scanlineDataPosition, 0);
                }

                scanlineData.AppendByte(ref scanlineDataPosition, dataRgba[i]);
                scanlinePosition++;
            }

            byte[] compressedScanlineData = PngEncoder.Compress(scanlineData);
            byte[] idatData     = new byte[1 + 1 + compressedScanlineData.Length + 4];
            int    idatPosition = 0;

            idatData.AppendByte(ref idatPosition, 0x78);                             // Zlib header
            idatData.AppendByte(ref idatPosition, 0x9C);                             // Zlib header
            idatData.AppendBytes(ref idatPosition, compressedScanlineData);          // Data
            idatData.AppendUInt(ref idatPosition, PngEncoder.Adler32(scanlineData)); // Adler32 checksum

            // Png
            byte[] png = new byte[8 + ihdrData.Length + 12 + idatData.Length + 12 + 12];

            // Position
            int position = 0;

            // Signature
            png.AppendByte(ref position, 0x89); // High bit set
            png.AppendByte(ref position, 0x50); // P
            png.AppendByte(ref position, 0x4E); // N
            png.AppendByte(ref position, 0x47); // G
            png.AppendByte(ref position, 0x0D); // DOS line ending
            png.AppendByte(ref position, 0x0A); // DOS line ending
            png.AppendByte(ref position, 0x1A); // DOS end of file
            png.AppendByte(ref position, 0x0A); // Unix line ending

            // Assemble
            png.AppendChunk(ref position, "IHDR", ihdrData);
            png.AppendChunk(ref position, "IDAT", idatData);
            png.AppendChunk(ref position, "IEND", new byte[0]);

            // Return
            return(png);
        }