Мало кому ныне не плевать на лишние килобайт-другой. Но такие люди есть, и как раз для такого задрота человека эта заметка и написана. )
В тех единичных случаях, когда мне нужно было записать выразительную иконку (.ico) приложения и одновременно следовало сэкономить байты, я пользовался следующим хаком: записывал изображение в 16-цветном режиме — но! — не в обычной фиксированной палитре, а в адаптивной.
Что это даёт? Иконка 48х48, 1-битовая прозрачность, 256 цветов = 3774 байта, она же в 16 цветах = 1662 байт. Выигрыш – 2 килобайта, при незначительном падении качества изображения.
Пример. Слева — направо:
- 256-цветный оригинал
- фиксированная стандартная 16-цветная палитра (причем здесь пару минут подбирал штриховку, чтоб изображение имело хоть сколько-нибудь приличный вид)
- адаптивная 16-цветная палитра + штриховка (dithering).
Как это работает? Как ни странно, 16-цветная иконка всегда носит в себе палитру. То есть, 99.9% старинных иконок несут в себе абсолютно одинаковую 64-байтную таблицу цветов (4 байта на цвет). И, да – оказывается, её можно перепрограммировать.
К сожалению, я не знаком с программой, что умеет полноценно работать с такого рода иконками. Поэтому вот рецепт, как «неполноценно» состряпать подобную иконку: возьмите IrfanView, загрузите в него картинку: либо заранее подготовленную 16-цветную, либо уменьшите количество цветов прямо в нём: меню – изображение – уменьшить глубину цвета… – 16 цветов. Теперь: меню – сохранить как… – выбрать формат .ico. Всё? Нет, не всё: Irfan View не умеет работать с прозрачностью, её придется восстановить вручную в другой программе. Microangelo Studio умеет загружать и редактировать такие иконки (увы, создавать из них библиотеку, ровно как и создавать такие иконки «с нуля» он не позволяет). Загружаем иконку в Microangelo и… возможно, с ходу получаем окошко с предупреждением насчет «некорректной палитры» — что это значит на практике, будет рассказано позже. Инструментами «заливка» и «карандаш» отмечаем прозрачные зоны; записываем; готово!
Это было то, что я делал раньше, лет десять назад. Теперь, внимательно присмотревшись к палитре Microangelo, у меня возникли вопросы. Что это за странная палитра, 18 цветов? Как вообще можно хранить 18 цветов в файле? Число-то не круглое, господа программисты так не поступают; им это просто не удобно. )) Видно, что в палитре есть сплошных 16 цветов и два служебных: «прозрачный» и «инверсный». Что за «инверсный»? – если такой цвет встречается, он отображает негатив того, что лежит под ним; используется это чаще всего в курсорах; а курсор – он и по сути и по структуре файла – тоже иконка. Но как хранятся все эти цвета? Если обычные точки изображения упакованы по 4 бита (16 цветов), то прозрачность может храниться только как отдельная битовая маска (1 бит на каждую точку изображения). Окей, а где же тогда хранится инверсия? Ещё одна маска, что ли? Не экономично, но возможно… Давайте-ка посчитаем.
Иконка 48х48, 16 цветов, 1 изображение. Размер файла 1662 байта. Что в нём? Я слабо представляю себе тонкости, но попробуем прикинуть. Главная часть, само изображение: 48*48/2 = 1152 байта. Палитра: 16*4 = 64 байта. Маска прозрачности 48*48/8 = 288 байт. Заголовок .ico, официально = 6 байт. Описание кадра (1 шт.) из документации = 16 байт. Итого: 1152+64+288+6+16 = 1526. Наверное, там есть что-то ещё, ведь реальный размер файла больше – но это не важно; важно другое, остаток «несходняка» мал: 136 байт, и он явно не позволяет разместить еще одну битовую маску размером 288 байт. Значит… инверсный цвет каким-то образом встроен в саму картинку. Может, теперь вы уж догадаетесь сами, как они это сделали?
А сделали они это, судя по всему, так: в оригинальных Windows (кажется, начиная с Win 95OSR2 полноценно, а в Win XP и более новых — уже частично), в иконках и курсорах, говоря строго — настоящего прозрачного цвета не существовало. Если альфа-маска показывала: текущая точка курсора/иконки «прозрачна» — брался цвет под курсором/иконкой и XOR-ился («исключающее “или”»; а может там было и просто вычитание) – внимание! – с текущим цветом точки, взятым из палитры иконки.
Что получается? Если это был первый цвет (черный в фиксированной палитре), XOR делал с фоном «ничего» — цвет становился просто прозрачным. Если это был последний цвет (в фиксированной палитре – белый) – цвет менялся полностью, превращался в негатив. Это и есть весь секрет, как хранились «18 цветов»… Т.е., еще раз: «прозрачный» = черный (+) альфа-маска, «инверсный» = белый (+) альфа-маска. А теперь – поговорим о «глюках».
Упомянутое выше предупреждение Microangelo гласит: «у вас в палитре нет полноценного белого и черного цветов, работа с прозрачностью будет некорректной!». И вправду, наша адаптивная палитра вполне может обойтись без черного или белого цветов. Как же тогда отработает прозрачность? О, именно так, как мы и ожидаем: возьмется какой-то цвет из палитры (например, зеленый), «отксорится» (XOR) с фоном, и мы получим прекрасный фиолетовый цвет вместо прозрачности. )) Или иной пример — на место последнего цвета в палитре случайно попал черный: и «инверсия» превратилась в обычную полноценную прозрачность.
Пример: слева стандартная палитра, справа перепрограммированная. Слева прозрачность (P) и инверсия (I) отрабатывают как надо; справа – явно нет.
Впрочем, все эти прелести иконок мы можем наблюдать только в оригинальных Windows. Современные ОС, такие как Win 10, игнорируют цвета палитры, и битовая маска «прозрачность» всегда работает именно как прозрачность в чистом виде: XOR-а нет, и инверсии соответственно нет тоже. Однако, в механизме отображения курсора, всё-таки есть совместимость – там работает полноценная старая добрая экономичная схема; «тёплая, ламповая», и… мало кому понятная и нужная.
Пример: различное отображение одних и тех же иконок в Windows XP и в Windows 7.
Автор: FishDude