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); }
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); }