예제 #1
0
 private static extern bool GetColorProfileHeader(IntPtr phProfile, out PROFILEHEADER pHeader);
예제 #2
0
        private ColorProfile(IntPtr handle)
        {
            var header = new PROFILEHEADER();

            if (!GetColorProfileHeader(handle, ref header))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            Size              = header.phSize;
            CmmType           = header.phCMMType;
            Version           = header.phVersion;
            Class             = header.phClass;
            DataColorSpace    = header.phDataColorSpace;
            ConnectionSpace   = header.phConnectionSpace;
            Signature         = header.phSignature;
            Platform          = header.phPlatform;
            IsEmbeddedProfile = (header.phProfileFlags & FLAG_EMBEDDEDPROFILE) != 0;
            IsDependentOnData = (header.phProfileFlags & FLAG_DEPENDENTONDATA) != 0;
            Manufacturer      = header.phManufacturer;
            Model             = header.phModel;
            Attributes        = header.phAttributes;
            Creator           = header.phCreator;
            RenderingIntent   = header.phRenderingIntent;
            Illuminant        = header.phIlluminant;

            var size = 0;

            if (!GetColorProfileFromHandle(handle, null, ref size))
            {
                var gle = Marshal.GetLastWin32Error();
                if (gle != ERROR_INSUFFICIENT_BUFFER)
                {
                    throw new Win32Exception(gle);
                }
            }

            Profile = new byte[size];
            if (!GetColorProfileFromHandle(handle, Profile, ref size))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            var localizedStrings = new Dictionary <string, List <string> >(StringComparer.OrdinalIgnoreCase);

            GetCountColorProfileElements(handle, out var count);
            for (var i = 0; i < count; i++)
            {
                if (GetColorProfileElementTag(handle, i + 1, out var tag))
                {
                    size = 0;
                    GetColorProfileElement(handle, tag, 0, ref size, null, out _);
                    if (size > 0)
                    {
                        var bytes = new byte[size];
                        if (GetColorProfileElement(handle, tag, 0, ref size, bytes, out _))
                        {
                            int offset;
                            // https://www.color.org/specification/ICC.2-2019.pdf
                            var type = Get4BytesString(BitConverter.ToInt32(bytes, 0));
                            switch (type)
                            {
                            case "text":
                                offset = 8;
                                switch (tag)
                                {
                                case 0x63707274:
                                    Copyright = getAscii(bytes.Length - 8);
                                    break;

                                case 0x74617267:
                                    RegisteredCharacterization = getAscii(bytes.Length - 8);
                                    break;

                                    //default:
                                    //    var s = getAscii(bytes.Length - 8);
                                    //    Console.WriteLine(tag.ToString("x8") + " => " + s);
                                    //    break;
                                }
                                break;

                            case "desc":
                                offset = 8;
                                var n = getInt32();
                                if (n > 0)
                                {
                                    switch (tag)
                                    {
                                    case 0x64657363:
                                        Description = getAscii(n);
                                        break;

                                    case 0x646d6e64:
                                        ManufacturerDescription = getAscii(n);
                                        break;

                                    case 0x646d6464:
                                        ModelDescription = getAscii(n);
                                        break;
                                    }
                                }

                                UnicodeLanguageCode = getInt32();
                                var m = getInt32();
                                if (m > 0)
                                {
                                    switch (tag)
                                    {
                                    case 0x64657363:
                                        Description = getUnicode(n);
                                        break;

                                    case 0x646d6464:
                                        ModelDescription = getUnicode(n);
                                        break;
                                    }
                                }
                                break;

                            case "mluc":     // multiLocalizedUnicodeType
                                offset = 8;
                                var records = getInt32();
                                _ = getInt32();     // record size
                                var languageCode = Get2BytesString(BitConverter.ToInt16(bytes, offset));
                                offset += 2;
                                var countryCode = Get2BytesString(BitConverter.ToInt16(bytes, offset));

                                var lcid = languageCode + "-" + countryCode;
                                offset += 2;
                                for (var ir = 0; ir < records; ir++)
                                {
                                    var sl = getInt32();
                                    var o  = offset;    // save
                                    offset = getInt32();
                                    var s = getBEUnicode(sl / 2);
                                    offset = o;     // restore

                                    if (!localizedStrings.TryGetValue(lcid, out var list))
                                    {
                                        list = new List <string>();
                                        localizedStrings.Add(lcid, list);
                                    }

                                    list.Add(s);
                                }
                                break;
                            }

                            int getInt32() => (bytes[offset++] << 24) | (bytes[offset++] << 16) | (bytes[offset++] << 8) | bytes[offset++];

                            string getAscii(int len)
                            {
                                var s = TrimTerminatingZeros(Encoding.ASCII.GetString(bytes, offset, len));

                                offset += len;
                                return(s);
                            }

                            string getBEUnicode(int len)
                            {
                                var s = TrimTerminatingZeros(Encoding.BigEndianUnicode.GetString(bytes, offset, len * 2));

                                offset += len;
                                return(s);
                            }

                            string getUnicode(int len)
                            {
                                var bom = BitConverter.ToInt16(bytes, offset);

                                if (bom == -2)
                                {
                                    offset += 3;
                                    len    -= 2;
                                }

                                var s = TrimTerminatingZeros(Encoding.Unicode.GetString(bytes, offset, len * 2));

                                offset += len;
                                return(s);
                            }
                        }
                    }
                }
            }

            LocalizedStrings = localizedStrings.ToDictionary(kv => kv.Key, kv => (IReadOnlyList <string>)kv.Value.AsReadOnly());
        }