Ловушки разработчика #1: ваша ICO выглядит нормально — пока не откроете BMP-кадры
2026-06-03
Tags: Windows · Ловушки разработчика
Это не очередная страшилка про сертификацию в Store. Это ловушка потише — и я попал в неё из чистого любопытства.
Долгие годы я генерировал .ico файлы одним и тем же ленивым способом: брал PNG 256×256, кидал в первый попавшийся онлайн-конвертер и забирал результат. В Проводнике всё выглядело отлично, так что я даже не задумывался.
А потом однажды, разрабатывая инструмент для распаковки ICO и тестируя ICO-файлы других продуктов, я обнаружил кое-что неприглядное.
Что я обнаружил
ICO-файл — это контейнер. В нём может храниться несколько изображений разных размеров (16×16, 32×32, 48×48, 64×64, 128×128, 256×256), чтобы Windows могла выбрать подходящий для каждого контекста — панели задач, заголовка окна, Alt+Tab, Проводника.
В моём ICO-файле каждый кадр на первый взгляд выглядел нормально. Но при ближайшем рассмотрении:
- Кадр 256×256 (хранится как PNG) — идеален. Нормальный альфа-канал, гладкие края, никаких артефактов.
- Все остальные BMP-кадры — прозрачность полностью испорчена. Альфа-канал либо отсутствовал, либо содержал мусор. Полупрозрачные пиксели превратились в сплошные блоки со странными цветными ореолами.
Мелкие выглядели как плохой хромакей из 90-х.
Почему онлайн-конвертеры портят ICO
Большинство бесплатных конвертеров PNG-to-ICO работают по такой схеме:
- Берут ваш PNG 256×256 и уменьшают до каждого нужного размера (16, 32, 48 и т.д.)
- Сохраняют кадр 256×256 как PNG
- Сохраняют мелкие кадры как 32-битный BMP
Однако формат BMP внутри ICO-файлов особенный. Он не использует навороченный BITMAPV5HEADER — он использует стандартный 40-байтовый BITMAPINFOHEADER с biBitCount, установленным в 32. 4-й байт каждого пикселя — это альфа-канал. И вот в чём загвоздка: после данных цветовых пикселей (XOR mask) обязательно должна идти 1-битная монохромная маска прозрачности (AND mask) для обратной совместимости. Кроме того, biHeight в заголовке должен быть установлен в удвоенную фактическую высоту изображения, чтобы учесть этот AND mask.
Многие онлайн-конвертеры ломаются именно здесь:
- Они объявляют 32-битный цвет, но заполняют альфа-байт (4-й байт) каждого пикселя значением
0x00(полностью прозрачный) или случайным мусором - Генерируемый ими AND mask полностью рассинхронизирован с данными альфа-канала
В результате — файл, который выглядит валидным: записи в каталоге верны, размеры совпадают, Проводник не жалуется, но когда Windows пытается отрендерить мелкие кадры, GDI blending сходит с ума. Появляются загадочные ореолы, прозрачные пиксели, которые на самом деле не прозрачны, и другие артефакты рендеринга.
Почему вы не заметите проблему, пока не станет поздно
Проводник Windows и большинство приложений предпочитают отображать кадр 256×256 в формате PNG. Раз он не тронут, иконка выглядит безупречно во всех обычных режимах — крупные значки, диалог свойств, даже предпросмотр на панели задач.
Сломанные BMP-кадры дают о себе знать только когда Windows нужно уменьшить иконку до определённого малого размера. Например:
| Контекст | Используемый размер | Какой кадр |
|---|---|---|
| Проводник (огромные значки) | 256×256 | PNG ✓ |
| Проводник (крупные/средние) | 48×48 | BMP ✗ |
| Заголовок окна / мелкий значок | 16×16 | BMP ✗ |
| Переключатель Alt+Tab | 32×32 | BMP ✗ |
Иконка вашего приложения может отлично смотреться на рабочем столе, но обзавестись загадочным «ореолом» или испорченной прозрачностью в заголовке окна или переключателе задач. Обычно винят рендеринг Windows. А дело в ICO.
Как проверить свои ICO-файлы
Существует множество бесплатных утилит, показывающих все кадры ICO-файла. Ищите:
- Формат кадра: Кадр 256px должен быть
PNG. Кадры меньшего размера —BMP. Использование PNG для всех кадров технически допустимо по спецификации ICO, но может вызвать проблемы совместимости на старых версиях Windows. Комбинация PNG (256px) + BMP (меньшие размеры) — самый безопасный вариант. - Глубина цвета BMP: Должно быть
32 BPPдля полноценной поддержки альфа-канала (полупрозрачное смешивание). Если написано24 BPP— попиксельные альфа-данные потеряны. Кадр всё ещё может использовать унаследованную 1-битную AND mask ICO для базовой обрезки фона по принципу «всё или ничего», но все сглаженные края, полупрозрачные градиенты и тени будут испорчены — они превратятся в уродливые сплошные артефакты или толстые чёрные контуры на современных системах. - Визуальная проверка: Откройте каждый кадр по отдельности. Мелкие кадры должны иметь правильную плавную прозрачность, а не рваные края или сплошной фон.
Как это исправить
Вариант 1: Используйте нормальный редактор иконок и протестируйте конвертер
Возьмите исходный PNG и создайте новый ICO в подходящем редакторе, который корректно обрабатывает альфа-канал BMP. Прежде чем доверять любому конвертеру — онлайн или офлайн — проведите тест: создайте ICO из PNG с заведомо полупрозрачными областями (мягкие тени, градиенты и т.п.), а затем проверьте каждый кадр. Если хотя бы один BMP-кадр имеет сломанную альфу — этот конвертер небезопасен для использования.
Вариант 2: ICO только с PNG (где возможно)
Некоторые современные инструменты принимают ICO-файлы, использующие сжатие PNG для всех кадров, а не только для 256×256. Это полностью исключает проблему с BMP-альфой. Однако такая возможность поддерживается не всеми версиями Windows и не всеми приложениями — тестируйте, прежде чем полагаться на неё.
Главные выводы
- То, что ICO нормально выглядит в Проводнике, ещё не значит, что с ним всё в порядке
- Кадр 256×256 в PNG обычно корректен; все остальные BMP-кадры могут быть сломаны
- Сломанная альфа в BMP невидна в большинстве режимов просмотра — она проявляется только в заголовках окон, Alt+Tab и других контекстах с мелкими значками
- Проверяйте онлайн-конвертер на PNG с заведомо полупрозрачными областями, прежде чем использовать его всерьёз
- Для всего, что вы поставляете пользователям, используйте нормальный редактор иконок — это стоит потраченных 5 минут
Эта статья входит в серию Ловушки разработчика.