Exemple #1
0
        /// <returns>Returns if this was the last chunk</returns>
        public static bool GenerateChunk(NativeArray <byte> data, int length, ref Metadata metadata)
        {
            ChunkType?chunkType = null;

            if (data[0] == 73 && data[1] == 72 && data[2] == 68 && data[3] == 82)
            {
                chunkType = ChunkType.IHDR;
            }
            else if (data[0] == 80 && data[1] == 76 && data[2] == 84 && data[3] == 69)
            {
                chunkType = ChunkType.PLTE;
            }
            else if (data[0] == 73 && data[1] == 68 && data[2] == 65 && data[3] == 84)
            {
                chunkType = ChunkType.IDAT;
            }
            else if (data[0] == 73 && data[1] == 69 && data[2] == 78 && data[3] == 68)
            {
                chunkType = ChunkType.IEND;
            }

            var isCriticalChunk = (data[0] & 32) == 0;

            if (chunkType == null)
            {
                if (isCriticalChunk)
                {
                    throw new NotImplementedException();
                }

                return(false);
            }

            //var isPublicChunk = (chunkTypeSpan[1] & 32) == 0;
            //var isCompatiblePNGVersion = (chunkTypeSpan[2] & 32) == 0;
            //var isSafeToCopy = (chunkTypeSpan[3] & 32) == 1;

            // CRC
            var expectedCRC   = BitConverterBigEndian.ToUInt32(data.Slice(4 + length, 4));
            var calculatedCRC = CRC32.Calculate(data.Slice(0, 4 + length));

            Debug.Assert(expectedCRC == calculatedCRC, "CRC check failed. The data seems to be damaged.");

            // Chunk Data
            switch (chunkType)
            {
            case ChunkType.IHDR:
                ReadIHDR(data.Slice(4, length), ref metadata);
                return(false);

            case ChunkType.IDAT:
                metadata.Data.AddRange(data.GetSubArray(4, length));     // TODO Replace with a native array
                return(false);

            case ChunkType.IEND:
                return(true);

            default:
                throw new Exception($"{nameof(chunkType)} matched no known types. Type was {GetASCIIString(data.Slice(0,4))}");
            }
        }
Exemple #2
0
        public void Execute()
        {
            //var fileStreamBuffer = FileData.Slice(0, 8);

            // This signature indicates that the remainder of the datastream contains a single PNG image, consisting of a series of chunks beginning with an IHDR chunk and ending with an IEND chunk.
            //Debug.Assert(fileStreamBuffer.SequenceEqual(pngSignature), "This doesn't seem to be a PNG");
            bool lastChunk;
            var  metadata = new Metadata(FileData.Length);
            var  offset   = 8;

            do
            {
                var length       = BitConverterBigEndian.ToUInt32(FileData.Slice(offset, 4));
                var signedLength = checked ((int)length);

                lastChunk = ChunkGenerator.GenerateChunk(FileData.GetSubArray(offset + 4, signedLength + 8), signedLength, ref metadata);
                offset   += 12 + signedLength;
            } while (!lastChunk);

            //var tmpScanlineColor = new Color32[metadata.Width];

            NativeArray <byte> uncompressedData;

            var metadataData = metadata.Data;
            var buffer       = metadataData.ToArray();

            using (var zlibStream = new ZlibStream(new MemoryStream(buffer), Ionic.Zlib.CompressionMode.Decompress)) {
                using (var memoryStream = new MemoryStream()) {
                    zlibStream.CopyTo(memoryStream);
                    uncompressedData = new NativeArray <byte>(memoryStream.ToArray(), Allocator.Temp);
                }
            }

            Debug.Assert(uncompressedData.Length >= 1);

            int bytesPerPixel;

            switch (metadata.ColourType)
            {
            case Metadata.ColourTypeEnum.GREYSCALE:
                bytesPerPixel = 1;
                throw new NotImplementedException();

            case Metadata.ColourTypeEnum.TRUECOLOUR:
                bytesPerPixel = 3;
                break;

            case Metadata.ColourTypeEnum.INDEXED_COLOUR:
                bytesPerPixel = 1;
                throw new NotImplementedException();

            case Metadata.ColourTypeEnum.GREYSCALE_WITH_ALPHA:
                bytesPerPixel = 2;
                throw new NotImplementedException();

            case Metadata.ColourTypeEnum.TRUECOLOUR_WITH_ALPHA:
                bytesPerPixel = 4;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            Width[0]  = checked ((int)metadata.Width);
            Height[0] = checked ((int)metadata.Height);
            RawTextureData.Resize(Width[0] * Height[0] * 4, NativeArrayOptions.UninitializedMemory);

            for (var aktLine = 0; aktLine < metadata.Height; aktLine++)
            {
                var firstRowBytePosition = aktLine * (Width[0] * bytesPerPixel + 1);
                //Color32[] lineColors = null;
                switch ((FilterType)uncompressedData[firstRowBytePosition])
                {
                case FilterType.NONE:
                    break;

                case FilterType.SUB:
                    FilterLineSub(ref uncompressedData, firstRowBytePosition, Width[0], bytesPerPixel);
                    break;

                case FilterType.UP:
                    FilterLineUp(ref uncompressedData, firstRowBytePosition, Width[0], bytesPerPixel);
                    break;

                case FilterType.AVERAGE:
                    FilterLineAverage(ref uncompressedData, firstRowBytePosition, Width[0], bytesPerPixel);
                    break;

                case FilterType.PAETH:
                    FilterLinePaeth(ref uncompressedData, firstRowBytePosition, Width[0], bytesPerPixel);
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                for (var i = 0; i < Width[0]; i++)
                {
                    RawTextureData[(int)((metadata.Height - 1 - aktLine) * metadata.Width * 4 + i * 4)]     = uncompressedData[firstRowBytePosition + 1 + i * bytesPerPixel];
                    RawTextureData[(int)((metadata.Height - 1 - aktLine) * metadata.Width * 4 + i * 4 + 1)] = uncompressedData[firstRowBytePosition + 2 + i * bytesPerPixel];
                    RawTextureData[(int)((metadata.Height - 1 - aktLine) * metadata.Width * 4 + i * 4 + 2)] = uncompressedData[firstRowBytePosition + 3 + i * bytesPerPixel];
                    RawTextureData[(int)((metadata.Height - 1 - aktLine) * metadata.Width * 4 + i * 4 + 3)] = bytesPerPixel == 4 ? uncompressedData[firstRowBytePosition + 4 + i * bytesPerPixel] : byte.MaxValue;
                }
            }
        }