private string GetTagDataString(int tagType)
        {
            try
            {
                var bytes = Directory.GetByteArray(tagType);
                if (bytes == null)
                {
                    return(Directory.GetString(tagType));
                }

                var reader = new ByteArrayReader(bytes);

                var iccTagType = (IccTagType)reader.GetInt32(0);

                switch (iccTagType)
                {
                case IccTagType.Text:
                {
#if !NETSTANDARD1_3
                    try
                    {
                        return(Encoding.ASCII.GetString(bytes, 8, bytes.Length - 8 - 1));
                    }
                    catch
#endif
                    {
                        return(Encoding.UTF8.GetString(bytes, 8, bytes.Length - 8 - 1));
                    }
                }

                case IccTagType.Desc:
                {
                    var stringLength = reader.GetInt32(8);
                    return(Encoding.UTF8.GetString(bytes, 12, stringLength - 1));
                }

                case IccTagType.Sig:
                {
                    return(IccReader.GetStringFromUInt32(reader.GetUInt32(8)));
                }

                case IccTagType.Meas:
                {
                    var observerType   = reader.GetInt32(8);
                    var x              = reader.GetS15Fixed16(12);
                    var y              = reader.GetS15Fixed16(16);
                    var z              = reader.GetS15Fixed16(20);
                    var geometryType   = reader.GetInt32(24);
                    var flare          = reader.GetS15Fixed16(28);
                    var illuminantType = reader.GetInt32(32);

                    string observerString;
                    switch (observerType)
                    {
                    case 0:
                        observerString = "Unknown";
                        break;

                    case 1:
                        observerString = "1931 2\u00b0";
                        break;

                    case 2:
                        observerString = "1964 10\u00b0";
                        break;

                    default:
                        observerString = $"Unknown ({observerType})";
                        break;
                    }

                    string geometryString;
                    switch (geometryType)
                    {
                    case 0:
                        geometryString = "Unknown";
                        break;

                    case 1:
                        geometryString = "0/45 or 45/0";
                        break;

                    case 2:
                        geometryString = "0/d or d/0";
                        break;

                    default:
                        geometryString = $"Unknown ({observerType})";
                        break;
                    }

                    string illuminantString;
                    switch (illuminantType)
                    {
                    case 0:
                        illuminantString = "unknown";
                        break;

                    case 1:
                        illuminantString = "D50";
                        break;

                    case 2:
                        illuminantString = "D65";
                        break;

                    case 3:
                        illuminantString = "D93";
                        break;

                    case 4:
                        illuminantString = "F2";
                        break;

                    case 5:
                        illuminantString = "D55";
                        break;

                    case 6:
                        illuminantString = "A";
                        break;

                    case 7:
                        illuminantString = "Equi-Power (E)";
                        break;

                    case 8:
                        illuminantString = "F8";
                        break;

                    default:
                        illuminantString = $"Unknown ({illuminantType})";
                        break;
                    }

                    return($"{observerString} Observer, Backing ({x:0.###}, {y:0.###}, {z:0.###}), Geometry {geometryString}, Flare {(long)Math.Round(flare*100)}%, Illuminant {illuminantString}");
                }

                case IccTagType.XyzArray:
                {
                    var res   = new StringBuilder();
                    var count = (bytes.Length - 8) / 12;

                    for (var i = 0; i < count; i++)
                    {
                        var x = reader.GetS15Fixed16(8 + i * 12);
                        var y = reader.GetS15Fixed16(8 + i * 12 + 4);
                        var z = reader.GetS15Fixed16(8 + i * 12 + 8);
                        if (i > 0)
                        {
                            res.Append(", ");
                        }
                        res.AppendFormat("({0:0.####}, {1:0.####}, {2:0.####})", x, y, z);
                    }

                    return(res.ToString());
                }

                case IccTagType.Mluc:
                {
                    var int1 = reader.GetInt32(8);
                    var res  = new StringBuilder();
                    res.Append(int1);
                    for (var i = 0; i < int1; i++)
                    {
                        var    str = IccReader.GetStringFromUInt32(reader.GetUInt32(16 + i * 12));
                        var    len = reader.GetInt32(16 + i * 12 + 4);
                        var    ofs = reader.GetInt32(16 + i * 12 + 8);
                        string name;
                        try
                        {
                            name = Encoding.BigEndianUnicode.GetString(bytes, ofs, len);
                        }
                        catch
                        {
                            name = Encoding.UTF8.GetString(bytes, ofs, len);
                        }
                        res.Append(" ").Append(str).Append("(").Append(name).Append(")");
                    }
                    return(res.ToString());
                }

                case IccTagType.Curv:
                {
                    var num = reader.GetInt32(8);
                    var res = new StringBuilder();
                    for (var i = 0; i < num; i++)
                    {
                        if (i != 0)
                        {
                            res.Append(", ");
                        }
                        res.Append(FormatDoubleAsString(reader.GetUInt16(12 + i * 2) / 65535.0, 7, false));
                    }
                    return(res.ToString());
                }

                default:
                {
                    return($"{IccReader.GetStringFromUInt32(unchecked((uint)iccTagType))} (0x{(int)iccTagType:X8}): {bytes.Length} bytes");
                }
                }
            }
            catch (IOException)
            {
                // TODO decode these values during IccReader.extract so we can report any errors at that time
                // It is convention to return null if a description cannot be formulated.
                // If an error is to be reported, it should be done during the extraction process.
                return(null);
            }
        }