Exemple #1
0
        /// <summary>
        /// Reads chunks before first IDAT. Position before: after IDHR (crc included)
        /// Position after: just after the first IDAT chunk id Returns length of first
        /// IDAT chunk , -1 if not found
        /// </summary>
        ///
        void ReadFirstChunks()
        {
            if (!FirstChunksNotYetRead())
            {
                return;
            }
            int  clen  = 0;
            bool found = false;

            byte[] chunkid = new byte[4]; // it's important to reallocate in each
            this.CurrentChunkGroup = ChunksList.CHUNK_GROUP_1_AFTERIDHR;
            while (!found)
            {
                clen    = PngHelperInternal.ReadInt4(inputStream);
                offset += 4;
                if (clen < 0)
                {
                    break;
                }
                PngHelperInternal.ReadBytes(inputStream, chunkid, 0, 4);
                offset += 4;
                if (PngCsUtils.arraysEqual4(chunkid, Pngcs.Chunks.ChunkHelper.b_IDAT))
                {
                    found = true;
                    this.CurrentChunkGroup = ChunksList.CHUNK_GROUP_4_IDAT;
                    // add dummy idat chunk to list
                    chunksList.AppendReadChunk(new PngChunkIDAT(ImgInfo, clen, offset - 8), CurrentChunkGroup);
                    break;
                }
                else if (PngCsUtils.arraysEqual4(chunkid, Pngcs.Chunks.ChunkHelper.b_IEND))
                {
                    throw new PngjInputException("END chunk found before image data (IDAT) at offset=" + offset);
                }
                string chunkids = ChunkHelper.ToString(chunkid);
                if (chunkids.Equals(ChunkHelper.PLTE))
                {
                    this.CurrentChunkGroup = ChunksList.CHUNK_GROUP_2_PLTE;
                }
                ReadChunk(chunkid, clen, false);
                if (chunkids.Equals(ChunkHelper.PLTE))
                {
                    this.CurrentChunkGroup = ChunksList.CHUNK_GROUP_3_AFTERPLTE;
                }
            }
            int idatLen = found ? clen : -1;

            if (idatLen < 0)
            {
                throw new PngjInputException("first idat chunk not found!");
            }
            iIdatCstream = new PngIDatChunkInputStream(inputStream, idatLen, offset);
            idatIstream  = ZlibStreamFactory.createZlibInputStream(iIdatCstream, true);
            if (!crcEnabled)
            {
                iIdatCstream.DisableCrcCheck();
            }
        }
Exemple #2
0
        /// <summary>
        /// Reads (and processes ... up to a point) chunks after last IDAT.
        /// </summary>
        ///
        void ReadLastChunks()
        {
            CurrentChunkGroup = ChunksList.CHUNK_GROUP_5_AFTERIDAT;
            // PngHelper.logdebug("idat ended? " + iIdatCstream.isEnded());
            if (!iIdatCstream.IsEnded())
            {
                iIdatCstream.ForceChunkEnd();
            }
            int clen = iIdatCstream.GetLenLastChunk();

            byte[] chunkid  = iIdatCstream.GetIdLastChunk();
            bool   endfound = false;
            bool   first    = true;
            bool   skip     = false;

            while (!endfound)
            {
                skip = false;
                if (!first)
                {
                    clen    = PngHelperInternal.ReadInt4(inputStream);
                    offset += 4;
                    if (clen < 0)
                    {
                        throw new PngjInputException("bad len " + clen);
                    }
                    PngHelperInternal.ReadBytes(inputStream, chunkid, 0, 4);
                    offset += 4;
                }
                first = false;
                if (PngCsUtils.arraysEqual4(chunkid, ChunkHelper.b_IDAT))
                {
                    skip = true; // extra dummy (empty?) idat chunk, it can happen, ignore it
                }
                else if (PngCsUtils.arraysEqual4(chunkid, ChunkHelper.b_IEND))
                {
                    CurrentChunkGroup = ChunksList.CHUNK_GROUP_6_END;
                    endfound          = true;
                }
                ReadChunk(chunkid, clen, skip);
            }
            if (!endfound)
            {
                throw new PngjInputException("end chunk not found - offset=" + offset);
            }
            // PngHelper.logdebug("end chunk found ok offset=" + offset);
        }
Exemple #3
0
        private void EndChunkGoForNext()
        {
            // Called after readging the last byte of chunk
            // Checks CRC, and read ID from next CHUNK
            // Those values are left in idLastChunk / lenLastChunk
            // Skips empty IDATS
            do
            {
                int crc = Pngcs.PngHelperInternal.ReadInt4(inputStream); //
                offset += 4;
                if (checkCrc)
                {
                    int crccalc = (int)crcEngine.GetValue();
                    if (lenLastChunk > 0 && crc != crccalc)
                    {
                        throw new PngjBadCrcException("error reading idat; offset: " + offset);
                    }
                    crcEngine.Reset();
                }
                lenLastChunk = Pngcs.PngHelperInternal.ReadInt4(inputStream);
                if (lenLastChunk < 0)
                {
                    throw new PngjInputException("invalid len for chunk: " + lenLastChunk);
                }
                toReadThisChunk = lenLastChunk;
                Pngcs.PngHelperInternal.ReadBytes(inputStream, idLastChunk, 0, 4);
                offset += 8;

                ended = !PngCsUtils.arraysEqual4(idLastChunk, Pngcs.Chunks.ChunkHelper.b_IDAT);
                if (!ended)
                {
                    foundChunksInfo.Add(new PngIDatChunkInputStream.IdatChunkInfo(lenLastChunk, (offset - 8)));
                    if (checkCrc)
                    {
                        crcEngine.Update(idLastChunk, 0, 4);
                    }
                }
                // PngHelper.logdebug("IDAT ended. next len= " + lenLastChunk + " idat?" +
                // (!ended));
            } while (lenLastChunk == 0 && !ended);
            // rarely condition is true (empty IDAT ??)
        }
Exemple #4
0
        /// <summary>
        /// Constructs a PNGReader objet from a opened Stream
        /// </summary>
        /// <remarks>The constructor reads the signature and first chunk (IDHR)<seealso cref="FileHelper.CreatePngReader(string)"/>
        /// </remarks>
        ///
        /// <param name="inputStream"></param>
        /// <param name="filename">Optional, can be the filename or a description.</param>
        public PngReader(Stream inputStream, string filename)
        {
            this.filename    = filename != null ? filename : string.Empty;
            this.inputStream = inputStream;
            this.chunksList  = new ChunksList(null);
            this.metadata    = new PngMetadata(chunksList);
            this.offset      = 0;
            // set default options
            this.CurrentChunkGroup  = -1;
            this.ShouldCloseStream  = true;
            this.MaxBytesMetadata   = 5 * 1024 * 1024;
            this.MaxTotalBytesRead  = 200 * 1024 * 1024; // 200MB
            this.SkipChunkMaxSize   = 2 * 1024 * 1024;
            this.SkipChunkIds       = new string[] { "fdAT" };
            this.ChunkLoadBehaviour = Pngcs.Chunks.ChunkLoadBehaviour.LOAD_CHUNK_ALWAYS;
            // starts reading: signature
            byte[] pngid = new byte[8];
            PngHelperInternal.ReadBytes(inputStream, pngid, 0, pngid.Length);
            offset += pngid.Length;
            if (!PngCsUtils.arraysEqual(pngid, PngHelperInternal.PNG_ID_SIGNATURE))
            {
                throw new PngjInputException("Bad PNG signature");
            }
            CurrentChunkGroup = ChunksList.CHUNK_GROUP_0_IDHR;
            // reads first chunk IDHR
            int clen = PngHelperInternal.ReadInt4(inputStream);

            offset += 4;
            if (clen != 13)
            {
                throw new System.Exception("IDHR chunk len != 13 ?? " + clen);
            }
            byte[] chunkid = new byte[4];
            PngHelperInternal.ReadBytes(inputStream, chunkid, 0, 4);
            if (!PngCsUtils.arraysEqual4(chunkid, ChunkHelper.b_IHDR))
            {
                throw new PngjInputException("IHDR not found as first chunk??? ["
                                             + ChunkHelper.ToString(chunkid) + "]");
            }
            offset += 4;
            PngChunkIHDR ihdr      = (PngChunkIHDR)ReadChunk(chunkid, clen, false);
            bool         alpha     = (ihdr.Colormodel & 0x04) != 0;
            bool         palette   = (ihdr.Colormodel & 0x01) != 0;
            bool         grayscale = (ihdr.Colormodel == 0 || ihdr.Colormodel == 4);

            // creates ImgInfo and imgLine, and allocates buffers
            ImgInfo      = new ImageInfo(ihdr.Cols, ihdr.Rows, ihdr.Bitspc, alpha, grayscale, palette);
            rowb         = new byte[ImgInfo.BytesPerRow + 1];
            rowbprev     = new byte[rowb.Length];
            rowbfilter   = new byte[rowb.Length];
            interlaced   = ihdr.Interlaced == 1;
            deinterlacer = interlaced ? new PngDeinterlacer(ImgInfo) : null;
            // some checks
            if (ihdr.Filmeth != 0 || ihdr.Compmeth != 0 || (ihdr.Interlaced & 0xFFFE) != 0)
            {
                throw new PngjInputException("compmethod or filtermethod or interlaced unrecognized");
            }
            if (ihdr.Colormodel < 0 || ihdr.Colormodel > 6 || ihdr.Colormodel == 1 ||
                ihdr.Colormodel == 5)
            {
                throw new PngjInputException("Invalid colormodel " + ihdr.Colormodel);
            }
            if (ihdr.Bitspc != 1 && ihdr.Bitspc != 2 && ihdr.Bitspc != 4 && ihdr.Bitspc != 8 &&
                ihdr.Bitspc != 16)
            {
                throw new PngjInputException("Invalid bit depth " + ihdr.Bitspc);
            }
        }