Пиксели, шаг строки, каналы и альфа

Пиксель, шаг строки, порядок каналов и альфа-канал на примере концептуального битмапа 4 на 3 пикселя в формате RGBA, с явными допущениями о выравнивании, ориентации строк и порядке байтов.

Концептуальный битмап 4 на 3 пикселя в формате RGBA: ячейки каналов, шаг строки и альфа-прозрачность

Пиксель и его каналы

Пиксель — минимальный адресуемый элемент изображения. В рассматриваемом примере каждый пиксель занимает четыре байта: по одному на каждый канал формата RGBA, где каналы идут в порядке красный, зелёный, синий и альфа. Три первых канала задают цвет, четвёртый — непрозрачность: значение 0 означает полную прозрачность, 255 — полную непрозрачность, промежуточные значения дают частичную прозрачность. Это выбранный для примера 8-битный формат; существуют и другие представления, например 16 бит на канал, плавающая точка или предумноженная альфа, где цветные каналы уже умножены на альфа.

Порядок каналов не является универсальным: встречаются варианты BGRA, ARGB и другие, и код, читающий битмап, обязан знать, в каком порядке каналы записаны. Кроме того, байты внутри многобайтового канала могут храниться в порядке little-endian или big-endian, а логический порядок каналов не всегда совпадает с порядком, в котором байты лежат в памяти.

Шаг строки

Строка битмапа содержит все пиксели одного горизонтального ряда. Шаг строки, или stride, — расстояние в байтах от начала строки до начала следующей. Он не всегда равен числу пикселей, умноженному на размер пикселя: многие форматы выравнивают каждую строку до кратного значения, например до четырёх или восьми байт, чтобы упростить адресацию. Байты заполнения между строками не относятся ни к одному пикселю.

Если шаг строки игнорировать и читать данные подряд, изображение начнёт смещаться после первой строки, и пиксели окажутся не на своих местах. Шаг строки задаётся метаданными изображения, а не выводится автоматически из ширины и размера пикселя: одно и то же изображение может иметь разные шаги в разных контейнерах. Выравнивание строк — обычная практика, но не гарантия скорости; конкретный выигрыш зависит от архитектуры процессора и способа доступа к памяти.

Пример битмапа 4 на 3 пикселя

Рассмотрим концептуальный битмап шириной 4 пикселя и высотой 3 строки в формате RGBA. Допустим, строки идут сверху вниз, шаг строки положительный и равен 16 байт, то есть выравнивание не добавляет байтов заполнения. Размер одного пикселя равен 4 байтам, поэтому длина полезной части строки составляет 16 байт, а всего в изображении 12 пикселей и 48 байт данных.

Первый пиксель — красный с полной непрозрачностью: байты FF 00 00 FF. Второй — полупрозрачный зелёный: 00 80 00 80. Третий — синий: 00 00 FF FF. Четвёртый — полностью прозрачный: 00 00 00 00. Вторая строка начинается сразу после 16-го байта, и так далее. Смещение пикселя с координатами x=2, y=1 в нулевой системе отсчёта равно y умножить на шаг строки плюс x умножить на размер пикселя: 1 умножить на 16 плюс 2 умножить на 4, итого 24 байта от начала буфера.

Если бы шаг строки был 32 байта, то же смещение составило бы 1 умножить на 32 плюс 2 умножить на 4, то есть 40 байт. Разница показывает, почему шаг строки нужно брать из метаданных, а не вычислять из ширины изображения.