public async Task <byte[]> DecodeAsync(byte[] imageBytes, ISffPngImageHeader imageHeader) { var scanlineDecoder = NegumContainer.Resolve <ISffPngScanlineDecoder>(); // -3 ==>> Scanline was interpreted as RGBA and we want it to be 1 byte not 4 // 4 ==>> RGBA (1 byte per each subPixel) var bytesPerLine = imageHeader.BytesInRow * 4 - 3; var bytesPerPixel = imageHeader.GetBytesPerPixel(); var outputBytes = new byte[imageBytes.Length]; for (var row = 0; row < imageHeader.Height; ++row) { var rowStartIndex = row * bytesPerLine; var rowEndIndex = rowStartIndex + bytesPerLine; var scanline = imageBytes[rowStartIndex..rowEndIndex];
public async Task <byte[]> DecodeAsync(Stream stream, ISffPngImageHeader imageHeader) { var chunkHeaderReader = NegumContainer.Resolve <ISffPngChunkHeaderReader>(); var chunkProcessorContainer = NegumContainer.Resolve <ISffPngChunkProcessorContainer>(); // State shared between all chunk processors. // Processors can use data read by other processors. var chunkProcessorState = new Dictionary <string, object>(); while (true) { if (chunkProcessorContainer.IsProcessingFinished(chunkProcessorState)) { break; } var chunkHeader = await chunkHeaderReader.ReadAsync(stream); var chunkData = new byte[chunkHeader.Length]; if (stream.Read(chunkData) != chunkHeader.Length) { throw new ArgumentException($"Cannot read chunk data."); } chunkProcessorContainer.ProcessChunk(chunkHeader, chunkData, chunkProcessorState); var crcData = new byte[SffPngHelper.CrcDataLength]; if (stream.Read(crcData) != SffPngHelper.CrcDataLength) { throw new ArgumentException($"Cannot read CRC data for chunk: {chunkHeader.Name}"); } // TODO: Do we need to validate CRC ??? (only critical) } chunkProcessorContainer.PerformPostProcessing(chunkProcessorState); var deflateImage = chunkProcessorContainer.GetOutputBytes(chunkProcessorState); return(deflateImage); }
public async Task <byte[]> ApplyAsync(ISffPngImageHeader imageHeader, byte[] imageData, IPalette palette) { // (Scanline filter byte + imageHeader.Width * 4 RGBA bytes) * imageHeader.Height == imageData.Length if ((1 + imageHeader.Width * 4) * imageHeader.Height == imageData.Length) { // Already in RGBA format return(imageData); } if (palette == null) { throw new ArgumentNullException($"Palette is required to decode PNG image."); } var coloredImage = new List <byte>(); for (var index = 0; index < imageData.Length; ++index) { var paletteIndex = imageData[index]; // For scanline filter type we don't want to perform colorization if (index == 0 || index % imageHeader.BytesInRow == 0) { coloredImage.Add(paletteIndex); continue; } var color = palette.ElementAt(paletteIndex); coloredImage.Add(color.Red); coloredImage.Add(color.Green); coloredImage.Add(color.Blue); coloredImage.Add(color.Alpha); } return(coloredImage.ToArray()); }
public async Task <byte[]> DecodeAsync(byte[] imageBytes, ISffPngImageHeader imageHeader) => imageHeader.InterlaceMethod switch { 0 => await NegumContainer.Resolve <ISffPngNoInterlaceDecoder>().DecodeAsync(imageBytes, imageHeader),
public async Task <byte[]> DecodeAsync(byte[] imageBytes, ISffPngImageHeader imageHeader) { throw new ArgumentException($"Adam7 interlace is not yet supported."); }