Esempio n. 1
0
 public DecodedPNGData(IdatChunk idatChunk, IhdrChunk ihdrChunk, PlteChunk plteChunk, string decodedIdat, string unfilteredDatastreamString, string filteredDatastreamString, byte[] unfilteredIdatDatastream, int scanlineLenght)
 {
     IdatChunk   = idatChunk;
     IhdrChunk   = ihdrChunk;
     PlteChunk   = plteChunk;
     DecodedIdat = decodedIdat;
     UnfilteredDatastreamString = unfilteredDatastreamString;
     FilteredDatastreamString   = filteredDatastreamString;
     UnfilteredIdatDatastream   = unfilteredIdatDatastream;
     ScanlineLenght             = scanlineLenght;
 }
Esempio n. 2
0
        public async Task CreatePngFile()
        {
            var header = new IhdrChunk(752, 1334, 8, ColorType.TruecolorAlpha);
            var idat   = new IdatChunk(header, rawRgbaData, FilterType);
            var end    = new IendChunk();

            var pngFile = new PngFile()
            {
                header,
                idat,
                end
            };

            using (var ms = new MemoryStream())
                await pngFile.WriteFileAsync(ms);
        }
Esempio n. 3
0
    /// <summary>
    /// Attempts to read XX bytes of the stream.
    /// </summary>
    internal static IdatChunk Read(uint length, byte[] array)
    {
        var chunk = new IdatChunk
        {
            Length    = length, //Chunk length, 4 bytes.
            ChunkType = "IDAT"  //Chunk type, 4 bytes.
        };

        using (var stream = new MemoryStream(array))
        {
            //Chunk details, XX bytes.
            chunk.FrameData = stream.ReadBytes(length); // - 4
        }

        return(chunk);
    }
Esempio n. 4
0
        internal DecodedPNGData DecodeByteArray(byte[] arrayByte)
        {
            IdatChunk idatChunk = ReadIdatChunk(arrayByte);
            PlteChunk plteChunk = ReadPlteChunk(arrayByte);
            IhdrChunk ihdrChunk = ReadIhdrChunk(arrayByte);

            int scanlineLenght = CalculateScanlineLenght(ihdrChunk);

            byte[] unfilteredIdatDatastream = UnfilterImageDatastream(scanlineLenght, idatChunk, ihdrChunk);

            string decodedBytes = PrintBytesToString(arrayByte, 8);
            string decodedAscii = PrintBytesToAsciiString(arrayByte);

            string decodedIdat = PrintBytesToString(idatChunk.DatastreamBytes, scanlineLenght);
            string unfilteredDatastreamString = PrintBytesToString(unfilteredIdatDatastream, scanlineLenght - 1);
            string filteredDatastreamString   = PrintBytesToString(idatChunk.DatastreamBytes, scanlineLenght);

            return(new DecodedPNGData(idatChunk, ihdrChunk, plteChunk, decodedIdat, unfilteredDatastreamString, filteredDatastreamString, unfilteredIdatDatastream, scanlineLenght));
        }
Esempio n. 5
0
        public async Task Can_write_PNG_file(string imageName, FilterType type, int bitDepth)
        {
            var asm      = typeof(PngFileTests).GetTypeInfo().Assembly;
            var resource = asm.GetManifestResourceStream(imageName);

            byte[] rawRgbaData;

            using (var ms = new MemoryStream()) {
                await resource.CopyToAsync(ms);

                rawRgbaData = ms.ToArray();
            }

            var header = new IhdrChunk(752, 1334, bitDepth, ColorType.TruecolorAlpha);
            var idat   = new IdatChunk(header, rawRgbaData, type);
            var end    = new IendChunk();

            var pngFile = new PngFile()
            {
                header,
                idat,
                end
            };

            var path = Path.Combine(Path.GetDirectoryName(asm.Location), $"Zooey-{bitDepth}-{type}.png");

            using (var fs = new FileStream(path, FileMode.Create))
                await pngFile.WriteFileAsync(fs);

            Assert.True(File.Exists(path));
            Assert.Equal(3, pngFile.ChunkCount);

            var result = ToolHelper.RunPngCheck(path);

            Assert.Equal(0, result.ExitCode);
            System.Console.Write(result.StandardOutput);
        }
Esempio n. 6
0
        internal ApngFrame GetFrame(int index)
        {
            //Build each frame using:
            //Starting blocks: IHDR, tIME, zTXt, tEXt, iTXt, pHYs, sPLT, (iCCP | sRGB), sBIT, gAMA, cHRM, PLTE, tRNS, hIST, bKGD.
            //Image data: IDAT.
            //End block: IEND.

            var chunks      = Chunks.Where(w => w.FrameGroupId == index).ToList();
            var otherChunks = Chunks.Where(w => w.FrameGroupId == -1 && w.ChunkType != "IDAT").ToList();

            if (!chunks.Any())
            {
                return(null);
            }

            var frame = new ApngFrame();

            //First frame • Second frame
            //Default image is part of the animation:       fcTL + IDAT • fcTL + fdAT
            //Default image isn't part of the animation:    IDAT • fcTL + fdAT

            if (chunks[0].ChunkType == "fcTL")
            {
                var fctl = FctlChunk.Read(chunks[0].Length, chunks[0].ChunkData);
                frame.Delay     = fctl.DelayNum == 0 ? 10 : (int)(fctl.DelayNum / (fctl.DelayDen == 0 ? 100d : fctl.DelayDen) * 1000d);
                frame.Width     = fctl.Width;
                frame.Height    = fctl.Height;
                frame.Left      = fctl.XOffset;
                frame.Top       = fctl.YOffset;
                frame.ColorType = Ihdr.ColorType;
                frame.BitDepth  = Ihdr.BitDepth;
                frame.DisposeOp = fctl.DisposeOp;
                frame.BlendOp   = fctl.BlendOp;

                using (var stream = new MemoryStream())
                {
                    //Png signature, 8 bytes.
                    stream.WriteBytes(new byte[] { 137, 80, 78, 71, 13, 10, 26, 10 });

                    //Image header chunk. 25 bytes.
                    Ihdr.Write(stream, fctl.Width, fctl.Height);

                    //Any other auxiliar chunks.
                    foreach (var other in otherChunks)
                    {
                        other.Write(stream);
                    }

                    //Frame has multiple chunks.
                    if (chunks.Count > 2)
                    {
                        var datas = new List <byte[]>();

                        //Data chunks.
                        for (var i = 1; i < chunks.Count; i++)
                        {
                            switch (chunks[i].ChunkType)
                            {
                            case "fdAT":
                            {
                                var fdat = FdatChunk.Read(chunks[i].Length, chunks[i].ChunkData);
                                datas.Add(fdat.FrameData);
                                break;
                            }

                            case "IDAT":
                            {
                                var idat = IdatChunk.Read(chunks[i].Length, chunks[i].ChunkData);
                                datas.Add(idat.FrameData);
                                break;
                            }
                            }
                        }

                        //Write combined frame data.
                        var length = datas.Sum(s => s.Length);

                        stream.WriteUInt32(BitHelper.ConvertEndian((uint)length));                                                                      //4 bytes.
                        stream.WriteBytes(Encoding.ASCII.GetBytes("IDAT"));                                                                             //4 bytes.
                        stream.WriteBytes(datas.SelectMany(s => s).ToArray());                                                                          //XX bytes.
                        stream.WriteUInt32(BitHelper.ConvertEndian(CrcHelper.Calculate(stream.PeekBytes(stream.Position - (length + 4), length + 4)))); //CRC, 4 bytes.
                    }
                    else
                    {
                        switch (chunks[1].ChunkType)
                        {
                        case "fdAT":
                        {
                            var fdat = FdatChunk.Read(chunks[1].Length, chunks[1].ChunkData);
                            fdat.Write(stream);
                            break;
                        }

                        case "IDAT":
                        {
                            var idat = IdatChunk.Read(chunks[1].Length, chunks[1].ChunkData);
                            idat.Write(stream);
                            break;
                        }
                        }
                    }

                    //End chunk.
                    stream.WriteUInt32(BitHelper.ConvertEndian(0u));                                                            //Chunk length, 4 bytes.
                    stream.WriteBytes(Encoding.ASCII.GetBytes("IEND"));                                                         //Chunk type, 4 bytes.
                    stream.WriteUInt32(BitHelper.ConvertEndian(CrcHelper.Calculate(stream.PeekBytes(stream.Position - 4, 4)))); //CRC, 4 bytes.

                    //Gets the whole Png.
                    frame.ImageData = stream.ToArray();
                }
            }
            else
            {
                //This is not supposed to happen.
                //All chunks with an FrameGroupId are grouped with a starting fcTL, ending with a IDAT or fdAT chunk.
                LogWriter.Log(new Exception("Missing fcTL on frame number " + index), $"It was not possible to read frame number {index}");
                return(null);
            }

            return(frame);
        }
Esempio n. 7
0
        private byte[] UnfilterImageDatastream(int scanlineLenght, IdatChunk idatChunk, IhdrChunk ihdrChunk)
        {
            //int datastreamLenght = chunkIhdr.height * chunkIhdr.width * scanlineLenght;
            byte[] datastreamIdat   = idatChunk.DatastreamBytes;
            int    datastreamLenght = datastreamIdat.Length;
            // Datastream after unfitering = size - amount of filter bytes
            int amountOfScanLines = ihdrChunk.Height;

            byte[] refilteredDatastream = new byte[datastreamLenght];

            // Lenght of the scanLine without filter byte
            int scanLineLenWithoutFilter = scanlineLenght - 1;

            // pixel size (in bytes)
            int pixelbytesLenght = 4;

            E_ColorType colorType = ihdrChunk.ColorType;

            if (colorType == E_ColorType.GRAYSCALE)
            {
                pixelbytesLenght = 1;
            }
            else if (colorType == E_ColorType.GRAYSCALE_ALPHA)
            {
                pixelbytesLenght = 2;
            }
            else if (colorType == E_ColorType.TRUECOLOR)
            {
                pixelbytesLenght = 3;
            }
            else if (colorType == E_ColorType.TRUECOLOR_ALPHA)
            {
                pixelbytesLenght = 4;
            }

            //Actual used scanLine and unfilteredScanLine
            byte[] tempScanline;          // Actual filtered scanline
            byte[] previousReconScanline; // Previous scanline which was reconstructed;
            byte[] unfilteredScanline = new byte[scanlineLenght - 1];

            for (int datastreamScanlineIter = 0; datastreamScanlineIter < amountOfScanLines; datastreamScanlineIter++)
            {
                int datastreamIter = (datastreamScanlineIter * (scanlineLenght));
                // Each iteration is on another scanline
                tempScanline = CutFromDatastream(datastreamIdat, datastreamIter, scanlineLenght);

                //Checking tempScanine FILTER TYPE:
                if (tempScanline[0] == 0)
                {
                    //  Console.WriteLine("--- Filter method 0: Non ---");
                    //NOTHING TO DO - FILTER 0
                    for (int scanLineIter = 1; scanLineIter < tempScanline.Length; scanLineIter++)
                    {
                        unfilteredScanline[scanLineIter - 1] = tempScanline[scanLineIter];
                    }
                }
                else if (tempScanline[0] == 1)
                {
                    //   Console.WriteLine("--- Filter method 1: Sub ---");

                    //Actual and previous used pixel (in bytes)
                    byte[] tempPixel   = new byte[pixelbytesLenght];
                    byte[] reconAPixel = new byte[pixelbytesLenght]; // recon(a) - pixel on the left to actual pixel (tempPiexl)
                    byte[] reconXPixel = new byte[pixelbytesLenght]; // recon(x) - reconstructed actual pixel;

                    // Pixel on the left from the first pixel in scanline stores 0 values
                    for (int k = 0; k < pixelbytesLenght; k++)
                    {
                        reconAPixel[k] = 0;
                    }

                    for (int scanLineIter = 1; scanLineIter < tempScanline.Length; scanLineIter += pixelbytesLenght)    // scanLineIter=1 becouse of filter byte
                    {
                        //Update pixel data
                        for (int k = 0; k < pixelbytesLenght; k++)
                        {
                            tempPixel[k] = tempScanline[scanLineIter + k];
                        }

                        for (int pixelIter = 0; pixelIter < pixelbytesLenght; pixelIter++)
                        {
                            reconXPixel[pixelIter] = (byte)(reconAPixel[pixelIter] + tempPixel[pixelIter]);
                            unfilteredScanline[scanLineIter + pixelIter - 1] = reconXPixel[pixelIter];
                            reconAPixel[pixelIter] = reconXPixel[pixelIter];
                        }
                    }
                }
                else if (tempScanline[0] == 2)
                {
                    //   Console.WriteLine("--- Filter method 2: Up ---");

                    //Actual and previous used pixel (in bytes)
                    byte[] tempPixel   = new byte[pixelbytesLenght];
                    byte[] reconBPixel = new byte[pixelbytesLenght]; // recon(b) - pixel above actual pixel (tempPiexl)


                    if (datastreamScanlineIter == 0)
                    {
                        previousReconScanline = new byte[scanlineLenght];
                    }
                    else
                    {
                        previousReconScanline = CutFromDatastream(refilteredDatastream, (datastreamIter - datastreamScanlineIter) - (scanlineLenght - 1), scanlineLenght - 1);
                    }

                    for (int scanLineIter = 1; scanLineIter < tempScanline.Length; scanLineIter += pixelbytesLenght)    // scanLineIter=1 becouse of filter byte
                    {
                        //Update pixel data
                        for (int k = 0; k < pixelbytesLenght; k++)
                        {
                            tempPixel[k] = tempScanline[scanLineIter + k];
                        }
                        for (int k = 0; k < pixelbytesLenght; k++)
                        {
                            reconBPixel[k] = previousReconScanline[scanLineIter - 1 + k];
                        }

                        for (int pixelIter = 0; pixelIter < pixelbytesLenght; pixelIter++)
                        {
                            unfilteredScanline[scanLineIter + pixelIter - 1] = (byte)(reconBPixel[pixelIter] + tempPixel[pixelIter]);
                        }
                    }
                }
                else if (tempScanline[0] == 3)
                {
                    //   Console.WriteLine("--- Filter method 3: Average ---");


                    byte[] tempPixel   = new byte[pixelbytesLenght]; //Actual and previous used pixel (in bytes)
                    byte[] reconBPixel = new byte[pixelbytesLenght]; // recon(b) - pixel above actual pixel (tempPiexl)
                    byte[] reconAPixel = new byte[pixelbytesLenght]; // recon(a) - pixel on the left to actual pixel (tempPiexl)
                    byte[] reconXPixel = new byte[pixelbytesLenght]; // recon(x) - reconstructed actual pixel;

                    if (datastreamScanlineIter == 0)
                    {
                        previousReconScanline = new byte[scanlineLenght]; // stores 0 if there is no previously reconstructed scanline
                    }
                    else
                    {
                        previousReconScanline = CutFromDatastream(refilteredDatastream, (datastreamIter - datastreamScanlineIter) - (scanlineLenght - 1), scanlineLenght - 1);
                    }

                    // Pixel on the left from the first pixel in scanline stores 0 values
                    for (int k = 0; k < pixelbytesLenght; k++)
                    {
                        reconAPixel[k] = 0;
                    }

                    for (int scanLineIter = 1; scanLineIter < tempScanline.Length; scanLineIter += pixelbytesLenght)    // scanLineIter=1 becouse of filter byte
                    {
                        //Update pixel data
                        for (int k = 0; k < pixelbytesLenght; k++)
                        {
                            tempPixel[k] = tempScanline[scanLineIter + k];
                        }
                        for (int k = 0; k < pixelbytesLenght; k++)
                        {
                            reconBPixel[k] = previousReconScanline[scanLineIter - 1 + k];
                        }

                        for (int pixelIter = 0; pixelIter < pixelbytesLenght; pixelIter++)
                        {
                            reconXPixel[pixelIter] = (byte)(tempPixel[pixelIter] + (reconBPixel[pixelIter] + reconAPixel[pixelIter]) / 2);
                            unfilteredScanline[scanLineIter + pixelIter - 1] = reconXPixel[pixelIter];
                            reconAPixel[pixelIter] = reconXPixel[pixelIter];
                        }
                    }
                }
                else if (tempScanline[0] == 4)
                {
                    //   Console.WriteLine("--- Filter method 4: PaethPredictor ---");

                    byte[] tempPixel    = new byte[pixelbytesLenght];
                    byte[] reconAPixel  = new byte[pixelbytesLenght]; // aPixel - pixel on the left to actual pixel
                    byte[] reconAPixel2 = new byte[pixelbytesLenght];
                    byte[] reconBPixel  = new byte[pixelbytesLenght]; // bPixel - pixel above actual pixel
                    byte[] reconCPixel  = new byte[pixelbytesLenght]; // cPixel - pixel on the left to bPixel pixel
                    byte[] reconXPixel  = new byte[pixelbytesLenght]; // recon(x) - reconstructed actual pixel;
                    byte[] reconPPixel  = new byte[pixelbytesLenght];

                    if (datastreamScanlineIter == 0)
                    {
                        previousReconScanline = new byte[scanlineLenght]; // stores 0 if there is no previously reconstructed scanline
                    }
                    else
                    {
                        previousReconScanline = CutFromDatastream(refilteredDatastream, (datastreamIter - datastreamScanlineIter) - (scanlineLenght - 1), scanlineLenght - 1);
                    }

                    for (int k = 0; k < pixelbytesLenght; k++)
                    {
                        // Pixel on the left from the first pixel in scanline stores 0 values
                        reconAPixel[k] = 0;
                        // Pixel on the above-left from the first pixel in scanline stores 0 values
                        reconCPixel[k] = 0;
                        // Pixel on the above from the first pixel in scanline stores 0 values
                        reconBPixel[k] = 0;
                    }

                    for (int scanLineIter = 1; scanLineIter < tempScanline.Length; scanLineIter += pixelbytesLenght)    // scanLineIter=1 becouse of filter byte
                    {
                        //Update pixel data
                        if (datastreamScanlineIter != 0)
                        {
                            for (int k = 0; k < pixelbytesLenght; k++)
                            {
                                reconBPixel[k] = previousReconScanline[scanLineIter - 1 + k];
                            }
                        }

                        if (scanLineIter != 1)
                        {
                            for (int k = 0; k < pixelbytesLenght; k++)
                            {
                                reconCPixel[k] = previousReconScanline[scanLineIter - 1 - pixelbytesLenght + k];
                            }
                        }

                        for (int k = 0; k < pixelbytesLenght; k++)
                        {
                            tempPixel[k]    = tempScanline[scanLineIter + k];
                            reconAPixel2[k] = reconAPixel[k];
                            reconXPixel[k]  = 0;
                            reconPPixel[k]  = 0;
                        }

                        for (int pixelIter = 0; pixelIter < pixelbytesLenght; pixelIter++)
                        {
                            int p, pa, pb, pc = 0;

                            p  = (reconAPixel2[pixelIter] + reconBPixel[pixelIter] - reconCPixel[pixelIter]);
                            pa = (Math.Abs(p - reconAPixel[pixelIter]));
                            pb = (Math.Abs(p - reconBPixel[pixelIter]));
                            pc = (Math.Abs(p - reconCPixel[pixelIter]));

                            if (pa <= pb && pa <= pc)
                            {
                                reconPPixel[pixelIter] = reconAPixel2[pixelIter];
                            }
                            else if (pb <= pc)
                            {
                                reconPPixel[pixelIter] = reconBPixel[pixelIter];
                            }
                            else
                            {
                                reconPPixel[pixelIter] = reconCPixel[pixelIter];
                            }

                            int x = (tempPixel[pixelIter] + reconPPixel[pixelIter]);
                            reconXPixel[pixelIter] = (byte)(tempPixel[pixelIter] + reconPPixel[pixelIter]);
                            unfilteredScanline[scanLineIter + pixelIter - 1] = reconXPixel[pixelIter];
                            reconAPixel[pixelIter] = reconXPixel[pixelIter];
                        }
                    }
                }
                else
                {
                    Console.WriteLine(" WRONG METHOD CODE !!!:  " + tempScanline[0] + "  Scanline: " + datastreamScanlineIter);
                    //NOTHING TO DO - FILTER 0
                    //for (int scanLineIter = 1; scanLineIter < tempScanline.Length; scanLineIter++)
                    //{
                    //    unfilteredScanline[scanLineIter - 1] = tempScanline[scanLineIter];
                    //}
                }

                // Fill refilteredDatastream with refiltered scanLine
                int refilteredDatastreamIter = datastreamScanlineIter * (scanlineLenght - 1);
                for (int k = 0; k < scanlineLenght - 1; k++) // k=1 becouse of filter byte
                {
                    refilteredDatastream[refilteredDatastreamIter + k] = unfilteredScanline[k];
                }
            }
            return(refilteredDatastream);
        }