public void ProcessChunk(string fourCc, byte[] payload)
        {
            switch (fourCc)
            {
                case "EXIF":
                {
                    _directories.AddRange(new ExifReader().Extract(new ByteArrayReader(payload)));
                    break;
                }
                case "ICCP":
                {
                    _directories.Add(new IccReader().Extract(new ByteArrayReader(payload)));
                    break;
                }
                case "XMP ":
                {
                    _directories.Add(new XmpReader().Extract(payload));
                    break;
                }
                case "VP8X":
                {
                    if (payload.Length != 10)
                        break;

                    IndexedReader reader = new ByteArrayReader(payload);
                    reader.IsMotorolaByteOrder = false;
                    try
                    {
                        // Flags
//                      var hasFragments = reader.getBit(0);
                        var isAnimation = reader.GetBit(1);
//                      var hasXmp = reader.getBit(2);
//                      var hasExif = reader.getBit(3);
                        var hasAlpha = reader.GetBit(4);
//                      var hasIcc = reader.getBit(5);
                        // Image size
                        var widthMinusOne = reader.GetInt24(4);
                        var heightMinusOne = reader.GetInt24(7);
                        var directory = new WebPDirectory();
                        directory.Set(WebPDirectory.TagImageWidth, widthMinusOne + 1);
                        directory.Set(WebPDirectory.TagImageHeight, heightMinusOne + 1);
                        directory.Set(WebPDirectory.TagHasAlpha, hasAlpha);
                        directory.Set(WebPDirectory.TagIsAnimation, isAnimation);
                        _directories.Add(directory);
                    }
                    catch (IOException e)
                    {
                        Debug.WriteLine(e);
                    }
                    break;
                }
                case "VP8L":
                {
                    if (payload.Length < 5)
                        break;

                    IndexedReader reader = new ByteArrayReader(payload);
                    reader.IsMotorolaByteOrder = false;
                    try
                    {
                        // https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification#2_riff_header

                        // Expect the signature byte
                        if (reader.GetByte(0) != 0x2F)
                            break;
                        var b1 = reader.GetByte(1);
                        var b2 = reader.GetByte(2);
                        var b3 = reader.GetByte(3);
                        var b4 = reader.GetByte(4);
                        // 14 bits for width
                        var widthMinusOne = (b2 & 0x3F) << 8 | b1;
                        // 14 bits for height
                        var heightMinusOne = (b4 & 0x0F) << 10 | b3 << 2 | (b2 & 0xC0) >> 6;
                        var directory = new WebPDirectory();
                        directory.Set(WebPDirectory.TagImageWidth, widthMinusOne + 1);
                        directory.Set(WebPDirectory.TagImageHeight, heightMinusOne + 1);
                        _directories.Add(directory);
                    }
                    catch (IOException e)
                    {
                        Debug.WriteLine(e);
                    }
                    break;
                }
                case "VP8 ":
                {
                    if (payload.Length < 10)
                        break;

                    IndexedReader reader = new ByteArrayReader(payload);
                    reader.IsMotorolaByteOrder = false;
                    try
                    {
                        // https://tools.ietf.org/html/rfc6386#section-9.1
                        // https://github.com/webmproject/libwebp/blob/master/src/enc/syntax.c#L115

                        // Expect the signature bytes
                        if (reader.GetByte(3) != 0x9D ||
                            reader.GetByte(4) != 0x01 ||
                            reader.GetByte(5) != 0x2A)
                            break;
                        var width = reader.GetUInt16(6);
                        var height = reader.GetUInt16(8);
                        var directory = new WebPDirectory();
                        directory.Set(WebPDirectory.TagImageWidth, width);
                        directory.Set(WebPDirectory.TagImageHeight, height);
                        _directories.Add(directory);
                    }
                    catch (IOException e)
                    {
                        Debug.WriteLine(e);
                    }
                    break;
                }
            }
        }
        private static IEnumerable<Face> ParseFaces(byte[] bytes, int firstRecordOffset, int posOffset, int recordLength)
        {
            if (bytes == null)
                yield break;

            var reader = new ByteArrayReader(bytes) { IsMotorolaByteOrder = false };

            int faceCount = reader.GetUInt16(0);

            if (faceCount == 0 || bytes.Length < firstRecordOffset + faceCount*recordLength)
                yield break;

            posOffset += firstRecordOffset;

            for (int i = 0, recordOffset = firstRecordOffset; i < faceCount; i++, recordOffset += recordLength, posOffset += recordLength)
            {
                yield return new Face(
                    x: reader.GetUInt16(posOffset),
                    y: reader.GetUInt16(posOffset + 2),
                    width: reader.GetUInt16(posOffset + 4),
                    height: reader.GetUInt16(posOffset + 6),
                    name: recordLength == 44 ? reader.GetString(recordOffset, 20, Encoding.ASCII).Trim(' ', '\0') : null,
                    age: recordLength == 44 ? Age.FromPanasonicString(reader.GetString(recordOffset + 28, 20, Encoding.ASCII).Trim(' ', '\0')) : null);
            }
        }
        public void ProcessChunk(string fourCc, byte[] payload)
        {
            switch (fourCc)
            {
                case "EXIF":
                {
                    _directories.AddRange(new ExifReader().Extract(new ByteArrayReader(payload)));
                    break;
                }
                case "ICCP":
                {
                    _directories.Add(new IccReader().Extract(new ByteArrayReader(payload)));
                    break;
                }
                case "XMP ":
                {
                    _directories.Add(new XmpReader().Extract(payload));
                    break;
                }
                case "VP8X":
                {
                    if (payload.Length != 10)
                        break;

                    IndexedReader reader = new ByteArrayReader(payload);
                    reader.IsMotorolaByteOrder = false;
                    try
                    {
                        // Flags
//                      var hasFragments = reader.getBit(0);
                        var isAnimation = reader.GetBit(1);
//                      var hasXmp = reader.getBit(2);
//                      var hasExif = reader.getBit(3);
                        var hasAlpha = reader.GetBit(4);
//                      var hasIcc = reader.getBit(5);
                        // Image size
                        var widthMinusOne = reader.GetInt24(4);
                        var heightMinusOne = reader.GetInt24(7);
                        var directory = new WebPDirectory();
                        directory.Set(WebPDirectory.TagImageWidth, widthMinusOne + 1);
                        directory.Set(WebPDirectory.TagImageHeight, heightMinusOne + 1);
                        directory.Set(WebPDirectory.TagHasAlpha, hasAlpha);
                        directory.Set(WebPDirectory.TagIsAnimation, isAnimation);
                        _directories.Add(directory);
                    }
                    catch (IOException e)
                    {
                        Console.Error.WriteLine(e);
                    }
                    break;
                }
            }
        }