Example #1
0
        private byte[] Decode(string path)
        {
            var result = new byte[0];

            using (var stream = new System.IO.FileStream(path, System.IO.FileMode.Open))
            {
                var header = new PngHeader(stream);

                var chunks = new List <PngChunk>();

                while (stream.Position < stream.Length)
                {
                    var chunk = new PngChunk(stream);

                    chunks.Add(chunk);

                    if (chunk.Type == "IEND")
                    {
                        break;
                    }
                }

                var ihdr     = chunks.Where(a => a.Type == "IHDR").FirstOrDefault();
                var ihdrData = ihdr.IRDRInfo;

                Width  = ihdrData.Width;
                Height = ihdrData.Height;

                var data = new List <byte>();

                for (var i = 0; i < chunks.Count; i++)
                {
                    if (chunks[i].Type == "IDAT")
                    {
                        data.AddRange(chunks[i].Data);
                    }
                }

                var pngData = new List <byte>();

                // The first byte 0x78 is called CMF, and the value means CM = 8, CINFO = 7. CM = 8 denotes the "deflate"
                // compression method with a window size up to 32K. This is the method used by gzip and PNG. CINFO = 7 indicates a
                // 32K window size.
                // The 0x9C is called FLG and the value means FLEVEL = 2, CHECK = 28.
                // The information in FLEVEL is not needed for decompression; it is there to indicate if recompression might be worthwhile.
                // CHECK is set to whatever value is necessary such that CMF*256 + FLG is a multiple of 31
                // we'll ignore the 2 bytees
                using (var deflate = new System.IO.Compression.DeflateStream(new System.IO.MemoryStream(data.Skip(2).Take(data.Count - 2).ToArray()), System.IO.Compression.CompressionMode.Decompress))
                {
                    var buffer = new byte[32768];

                    while (deflate.CanRead)
                    {
                        int count = deflate.Read(buffer, 0, buffer.Length);

                        pngData.AddRange(buffer.Take(count));

                        if (count < 32768)
                        {
                            break;
                        }
                    }
                }

                var bytesPerPixel = 3;
                _dataStructure = ImageDataStructure.Rgb;

                switch (ihdrData.ColorType)
                {
                case PngChunk.ColorTypeCode.ColorUsedAlphaChannelUsed:
                    bytesPerPixel  = 4;
                    _dataStructure = ImageDataStructure.Rgba;
                    break;
                }


                result = new byte[Width * Height * bytesPerPixel];
                var previousScanLine = new byte[Width * bytesPerPixel];
                var scanLine         = new byte[Width * bytesPerPixel];
                var pngArray         = pngData.ToArray();

                var dataLineWithFilter = Width * bytesPerPixel + 1;

                for (var i = 0; i < Height; i++)
                {
                    // first byte of each line specifies the filter
                    var filter = (PngChunk.FilterTypeCode)pngArray[dataLineWithFilter * i];

                    // copy the data of the scan line
                    Array.Copy(pngArray, dataLineWithFilter * i + 1, scanLine, 0, scanLine.Length);

                    previousScanLine = Defilter(filter, scanLine, previousScanLine, bytesPerPixel);

                    Array.Copy(previousScanLine, 0, result, scanLine.Length * i, scanLine.Length);
                }
            }

            return(result);
        }
Example #2
0
        public bool Save(string path)
        {
            try
            {
                using (var stream = new System.IO.FileStream(path, System.IO.FileMode.Create))
                {
                    var header = new PngHeader();

                    stream.Write(header.Data, 0, header.Data.Length);

                    PngChunk.Write(stream, "IHDR", PngChunk.CreateIHDRData(new PngChunk.IHDRData()
                    {
                        Width             = TransformedWidth,
                        Height            = TransformedHeight,
                        BitDepth          = 8,
                        ColorType         = PngChunk.ColorTypeCode.ColorUsedAlphaChannelUsed,
                        CompressionMethod = PngChunk.CompressionMethodCode.Deflate,
                        FilterMethod      = PngChunk.FilterTypeCode.None,
                        InterlaceMethod   = PngChunk.InterlaceMethodCode.None
                    }));

                    DataStructure = ImageDataStructure.Rgba;

                    var imageData = new byte[Data.Length + TransformedHeight];

                    for (int i = 0; i < TransformedHeight; i++)
                    {
                        imageData[i * TransformedWidth * 4 + i] = (byte)PngChunk.FilterTypeCode.None;
                        Array.Copy(Data, i * TransformedWidth * 4, imageData, i * TransformedWidth * 4 + i + 1, TransformedWidth * 4);
                    }

                    using (var idatStream = new MemoryStream())
                    {
                        idatStream.WriteByte(0x78);
                        idatStream.WriteByte(0x9C);

                        using (var deflate = new System.IO.Compression.DeflateStream(idatStream, System.IO.Compression.CompressionMode.Compress))
                        {
                            var window = 32768;
                            var count  = 0;

                            while (count * window < imageData.Length)
                            {
                                var buffer = imageData.Skip(count * window).Take(window).ToArray();
                                deflate.Write(buffer, 0, buffer.Length);
                                count++;
                            }

                            deflate.Dispose();
                            PngChunk.Write(stream, "IDAT", idatStream.ToArray());
                        }
                    }

                    PngChunk.Write(stream, "IEND", new byte[0]);
                }
            }
            catch (Exception)
            {
                return(false);
            }

            return(true);
        }