Skip to content

Ловушки разработчика #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 работают по такой схеме:

  1. Берут ваш PNG 256×256 и уменьшают до каждого нужного размера (16, 32, 48 и т.д.)
  2. Сохраняют кадр 256×256 как PNG
  3. Сохраняют мелкие кадры как 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×256PNG ✓
Проводник (крупные/средние)48×48BMP ✗
Заголовок окна / мелкий значок16×16BMP ✗
Переключатель Alt+Tab32×32BMP ✗

Иконка вашего приложения может отлично смотреться на рабочем столе, но обзавестись загадочным «ореолом» или испорченной прозрачностью в заголовке окна или переключателе задач. Обычно винят рендеринг 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 минут

Эта статья входит в серию Ловушки разработчика.