public IccDirectory Extract([NotNull] IndexedReader reader)
        {
            // TODO review whether the 'tagPtr' values below really do require IndexedReader or whether SequentialReader may be used instead
            var directory = new IccDirectory();

            try
            {
                var profileByteCount = reader.GetInt32(IccDirectory.TagProfileByteCount);
                directory.Set(IccDirectory.TagProfileByteCount, profileByteCount);

                // For these tags, the int value of the tag is in fact its offset within the buffer.
                Set4ByteString(directory, IccDirectory.TagCmmType, reader);
                SetInt32(directory, IccDirectory.TagProfileVersion, reader);
                Set4ByteString(directory, IccDirectory.TagProfileClass, reader);
                Set4ByteString(directory, IccDirectory.TagColorSpace, reader);
                Set4ByteString(directory, IccDirectory.TagProfileConnectionSpace, reader);
                SetDate(directory, IccDirectory.TagProfileDateTime, reader);
                Set4ByteString(directory, IccDirectory.TagSignature, reader);
                Set4ByteString(directory, IccDirectory.TagPlatform, reader);
                SetInt32(directory, IccDirectory.TagCmmFlags, reader);
                Set4ByteString(directory, IccDirectory.TagDeviceMake, reader);

                var model = reader.GetInt32(IccDirectory.TagDeviceModel);
                if (model != 0)
                {
                    directory.Set(IccDirectory.TagDeviceModel, model <= 0x20202020
                        ? (object)model
                        : GetStringFromUInt32(unchecked ((uint)model)));
                }

                SetInt32(directory, IccDirectory.TagRenderingIntent, reader);
                SetInt64(directory, IccDirectory.TagDeviceAttr, reader);

                var xyz = new[] { reader.GetS15Fixed16(IccDirectory.TagXyzValues), reader.GetS15Fixed16(IccDirectory.TagXyzValues + 4), reader.GetS15Fixed16(IccDirectory.TagXyzValues + 8) };
                directory.Set(IccDirectory.TagXyzValues, xyz);

                // Process 'ICC tags'
                var tagCount = reader.GetInt32(IccDirectory.TagTagCount);
                directory.Set(IccDirectory.TagTagCount, tagCount);

                for (var i = 0; i < tagCount; i++)
                {
                    var pos     = IccDirectory.TagTagCount + 4 + i * 12;
                    var tagType = reader.GetInt32(pos);
                    var tagPtr  = reader.GetInt32(pos + 4);
                    var tagLen  = reader.GetInt32(pos + 8);
                    var b       = reader.GetBytes(tagPtr, tagLen);
                    directory.Set(tagType, b);
                }
            }
            catch (Exception ex)
            {
                directory.AddError("Exception reading ICC profile: " + ex.Message);
            }

            return(directory);
        }
        private static void SetDate([NotNull] IccDirectory directory, int tagType, [NotNull] IndexedReader reader)
        {
            var year    = reader.GetUInt16(tagType);
            var month   = reader.GetUInt16(tagType + 2);
            var day     = reader.GetUInt16(tagType + 4);
            var hours   = reader.GetUInt16(tagType + 6);
            var minutes = reader.GetUInt16(tagType + 8);
            var seconds = reader.GetUInt16(tagType + 10);

            if (DateUtil.IsValidDate(year, month, day) &&
                DateUtil.IsValidTime(hours, minutes, seconds))
            {
                directory.Set(tagType, new DateTime(year, month, day, hours, minutes, seconds, kind: DateTimeKind.Utc));
            }
            else
            {
                directory.AddError($"ICC data describes an invalid date/time: year={year} month={month} day={day} hour={hours} minute={minutes} second={seconds}");
            }
        }