Bloometry

This article is also available in English.

Здравствуй, дорогой читатель. Это свершилось – я разместил своё первое рабочее приложение в Google Play. Скачать можно по ссылке либо на официальном сайте. А в этом посте кратко расскажу о его жизненном пути.

Предыстория

Реализовать неказуальный игровой проект в одиночку и монетизировать его – не такая уж быстрая задача. К тому же в свете известных всем событий возникла необходимость заняться более приземлёнными прагматичными вещами.

На полке запылившихся проектов у меня давно валялось полусырое приложение для дизайнеров/печатников, нацеленное на упрощение самых разных задач, связанных с цветом. Среди них подбор цветовых гамм, извлечение основных цветов из фото, механическое смешение, поиск ближайших оттенков в популярных цветовых палитрах и системах, измерение Delta-E и множество других специфичных функций навроде построения спектральных кривых.

Работа над этим приложением давно остановилась, поскольку, как вы могли заметить, список задач я взял обширный, и в тот момент мне казалось, что я должен реализовать их все и сразу. Что это было: максимализм, перфекционизм, супергероизм – сейчас сказать сложно.

Самое смешное, что у меня была готова собственная .NET библиотека для работы с цветами и их преобразований. Были дополнительные надстроечные модули, каждый из которых предоставлял возможности решения поставленных выше задач. Было и чёткое понимание того, как подключить сторонние библиотеки (и это важно, потому что они делают Bloometry отличным от других подобных приложений).

Можно только спросить себя: как же так, ведь у тебя были на руках все кусочки паззла, почему не удалось соединить их воедино ещё тогда? Ответ кроется в том, что нельзя просто взять их все одновременно и сложить в цельную картину. Возможно, если у тебя детская мозаика из 10 элементов, то что-то и получится. Но если фрагментов куда больше, то всё равно придётся собирать что-то отдельно, формировать более крупные части, прибегать к хитростям навроде собирания общей рамки или поиска закономерностей в нарезке кусочков.

Тогда я переоценил свои силы и взялся за всё сразу. К счастью, нынешний я стал по-другому смотреть на некоторые вещи, и два месяца назад мне в голову пришла идея вернуться к этому проекту, разделив его на отдельные этапы. А для стартового запуска взять самые общие задачи – создание цветовых схем вручную и на основе изображений.

Детали реализации

Многие знают, что экраны наших устройств отображают цвета на основе модели RGB (красный – зелёный – синий). По крайней мере, слышали об этом. Кто-то так же знает, что для печати используется другая цветовая модель – CMYK (голубой – пурпурный – жёлтый – чёрный).

Чтобы задать цвет, мы просто указываем, сколько в нём должно присутствовать того или иного компонента (например, R = 255, G = 0, B = 0 – это красный). Но прелесть в том, что числовые значения RGB или CMYK сами по себе ничего не значат. Точно так же, как ничего не значат, например, координаты X = 10, Y = 20, Z = 30. Чтобы их использовать, а уж тем более преобразовывать друг в друга, необходимо задать какую-то систему отсчёта. В случае с цветами – обозначить цветовое пространство. Только тогда ваш компьютер, а вместе с ним монитор или принтер, смогут понять, какой цвет требуется воспроизвести.

Один из универсальных способов задания подобных цветовых пространств – это ICC-профили, стандарт для которых был разработан не абы кем, а Международным консорциумом по цвету. Те, кто плотно работает с Photoshop, Illustrator, InDesign или CorelDRAW наверняка сталкивались с ними, поскольку в таких профессиональных редакторах возможность их использования и перенастройки жизненно необходима.

Но в более простых утилитах дела обстоят по-другому. Они напрочь игнорируют факт существования разных цветовых пространств и предлагают для работы некие абстрактные модели RGB, CMYK, Lab или другие. Мне всегда казалось это странным, поскольку совершенно непонятно, из чего и во что они преобразуют, и как использовать полученные после преобразования цифры. Ну то есть использовать-то их можно, но насколько это будет корректно? Для примера я вам покажу, как выглядит цвет с компонентами R = 30, G = 130, B = 190 в пяти различных пространствах: sRGB, Adobe RGB, Apple RGB, ProPhoto и Wide Gamut.

Sample RGB swatches

Нужно сделать оговорку: ваш экран, скорее всего, работает с пространством sRGB, и реальные цвета отличаются от тех, которые вы видите. В любом случае, заметить отличия несложно. Именно поэтому в Bloometry я решил чётко разделить понятия цветовой модели и цветового пространства. После указания модели вам будет предложено в соответствующем поле выбрать конкретное пространство. А при возможности ещё и «подгрузить» ICC-профиль (что уж совсем космос 😀🚀).

Есть и другая немаловажная деталь, на которую разработчики дизайнерских приложений почему-то часто не обращают внимания – цветовой круг. Так уж повелось, что художники пользуются цветовым кругом Иттена на основе триады RYB (красный – жёлтый – синий), из которой путём смешивания получают другие оттенки. А вот дисплеи оперируют уже упомянутыми выше компонентами RGB, и цветовой круг для этой модели отличается (в кодировке HSL/HSV за позицию на круге отвечает компонент Hue – оттенок). И здесь возникают проблемы.

На изображении я разместил «классический» цветовой круг снаружи, а цветовой круг RGB – внутри. На первый взгляд, разница не так уж и велика. Но если мы решим найти на этих кругах контрастные (комплементарные) цвета, то обнаружим, например, что в классическом варианте это вполне себе привычная пара красный – зелёный, а вот в варианте RGB противоположным красному станет голубой. С точки зрения цифр все корректно – и там, и там цвета отделяет угол в 180 градусов. Но вот с точки зрения восприятия контраст в первом случае всё же считается сильнее.

Для примера я привёл ещё несколько образцов контрастных цветов. В левом столбце – «классика», в правом – RGB (образцы не выровнены по яркости/насыщенности). В Bloometry, конечно же, реализован более устоявшийся цветовой круг с красным, жёлтым и синим в качестве основных цветов.

Философия проекта

В предыдущем разделе я описал одни из самых ярких деталей, которые отличают Bloometry от других служб и приложений подобного рода. Наверное, они несколько усложняют функционал всего проекта и могут отпугнуть часть пользователей, но мне всё же видится, что лучше иметь возможность настроить что-то более детально, чем не иметь её вообще. С другой стороны, я уже рассматриваю для внедрения возможность переключения интерфейса между режимами «простой»/«профессиональный», которая могла бы решить данный вопрос.

В целом, как вы уже могли понять, я решил подойти к делу более основательно и «научно». В этом отношении мой максимализм/перфекционизм никуда не делся, поэтому в каждый элемент приложения я вкладываю стремление копнуть глубже и сделать детальнее. Сможет ли такое стремление дать свои плоды – вопрос интересный. Возможно, он даже лежит в плоскости того, должны ли мы делать то, что нам кажется правильным, или то, что будет более популярным.

Сейчас Bloometry, пожалуй, выглядит проще и незатейливее того фундамента, который в него заложен. Отчасти это даже хорошо, ведь пользователь не должен знать о подводной части айсберга. Однако с постепенным введением всего запланированного функционала, я уверен, весь массив этого проекта на полную заиграет своими разноцветными красками.


Здесь заканчивается лирическая часть моего повествования. Спасибо за прочтение. Для страждущих оставлю в качестве послесловия ещё один раздел.

Технические тонкости

Bloometry реализовано с помощью Xamarin.Forms, поскольку C# остаётся моим основным рабочим инструментом. Да и возможность написания кроссплатформенных решений для независимого разработчика – это всё же больше плюс, чем минус, поскольку пресловутые человеко-часы никто не отменял, и необходимо как можно больше кода сделать независимым от целевой платформы. По итогу могу сказать, что даже с обилием кастомных UI-элементов, примерно 70% кода осталось общим (а если учитывать библиотеки, то и все 80–90).

В сердце проекта – моя собственная библиотека для работы с цветами Scol. Математическая модель преобразований основана на формулах с широко известного в узких кругах сайта Брюса Линдблума (Bruce Lindbloom). Извлечение цветов производится с помощью методов машинного обучения, реализованных в Accord.NET. Смешение и построение спектральных кривых отчасти базируется на идеях с этого прекрасного сайта, отчасти – на теории Кубельки-Мунка (Kubelka-Munk theory), отчасти – на моих способностях к реверс-инжинирингу (но это уже совсем другая история). Экспорт в различные форматы сделан на основе (не)официальных спецификаций в зависимости от того или иного типа файла.

Не обошлось и без использования других языков. Для интеграции рекламной платформы потребовались Android-библиотеки, написанные на Java, которые после танцев с бубнами всё же интегрировались в проект и повели себя вполне буднично по отношению к окружению. Смимикрировали, так сказать, как будто бы они изначально были написаны для .NET. Далее на очереди – что-нибудь аналитическое навроде Google Analytics или Flurry.

А вот для особого функционала, связанного с ICС-профилями, пришлось прибегать к более тяжёлым веществам тяжёлой артиллерии – языку C и библиотеке Little CMS. Изначально я писал свою собственную обёртку через P/Invoke, но за то время, пока приложение пылилось на полке, вышла готовая библиотека lcmsNET. Дело оставалось только за тем, чтобы скомпилировать сишный код с помощью Android NDK. На выходе получаются несколько файлов под каждую архитектуру процессора, которые без проблем добавляются к проекту.