diff --git a/Minint.Infrastructure/Export/BmpExporter.cs b/Minint.Infrastructure/Export/BmpExporter.cs index e0f49fd..78df389 100644 --- a/Minint.Infrastructure/Export/BmpExporter.cs +++ b/Minint.Infrastructure/Export/BmpExporter.cs @@ -31,32 +31,46 @@ public sealed class BmpExporter : IBmpExporter w.Write(fileSize); w.Write((ushort)0); // reserved1 w.Write((ushort)0); // reserved2 - w.Write(HeadersTotal); // pixel data offset + w.Write(HeadersTotal); // bfOffBits — смещение до пикселей от начала файла - // BITMAPV4HEADER (108 bytes) + // --- BITMAPV4HEADER (108 байт, см. WinGDI BITMAPV4HEADER) --- + // Поля ниже идут подряд, little-endian. Расширяет BITMAPINFOHEADER полями + // масок каналов (как при BI_BITFIELDS), типом цветового пространства и гаммой. + + // bV4Size (4) — размер этой структуры в байтах; обязательно 108 для V4. w.Write(BitmapV4HeaderSize); + // bV4Width (4) — ширина растра в пикселях. w.Write(width); - w.Write(height); // positive = bottom-up - w.Write((ushort)1); // planes - w.Write((ushort)32); // bpp - w.Write(3); // biCompression = BI_BITFIELDS + // bV4Height (4) — высота. Значение > 0: строки снизу вверх (первый байт строки — нижняя линия изображения). + w.Write(height); + // bV4Planes (2) — число цветовых плоскостей, для BMP всегда 1. + w.Write((ushort)1); + // bV4BitCount (2) — бит на пиксель; 32 = BGRA по байтам в строке. + w.Write((ushort)32); + // bV4Compression (4) — BI_BITFIELDS (3): цвета кодируются масками bV4*Mask, не таблицей. + w.Write(3); + // bV4SizeImage (4) — размер сырого bitmap в байтах (здесь width*height*4). w.Write(imageSize); - w.Write(2835); // X pixels per meter (~72 DPI) - w.Write(2835); // Y pixels per meter - w.Write(0); // colors used - w.Write(0); // important colors + // bV4XPelsPerMeter, bV4YPelsPerMeter (по 4) — разрешение для метаданных (~2835 ≈ 72 DPI). + w.Write(2835); + w.Write(2835); + // bV4ClrUsed (4) — число используемых индексов палитры; 0 для полного 32 bpp. + w.Write(0); + // bV4ClrImportant (4) — «важных» цветов; 0 = все. + w.Write(0); - // Channel masks (BGRA order in file) - w.Write(0x00FF0000u); // red mask - w.Write(0x0000FF00u); // green mask - w.Write(0x000000FFu); // blue mask - w.Write(0xFF000000u); // alpha mask + // Маски извлечения каналов из DWORD пикселя (порядок записи: R, G, B, A). + // В памяти строки: B, G, R, A (младший байт — B); DWORD при little-endian совпадает с 0xAARRGGBB. + w.Write(0x00FF0000u); // bV4RedMask + w.Write(0x0000FF00u); // bV4GreenMask + w.Write(0x000000FFu); // bV4BlueMask + w.Write(0xFF000000u); // bV4AlphaMask - // Color space type: LCS_sRGB - w.Write(0x73524742); // 'sRGB' - // CIEXYZTRIPLE endpoints (36 bytes zeroed) + // bV4CSType (4) — LCS_sRGB: 0x73524742 ('sRGB' в ASCII как little-endian DWORD). + w.Write(0x73524742); + // bV4Endpoints (36) — CIEXYZTRIPLE (координаты для профиля); для sRGB не используем — нули. w.Write(new byte[36]); - // Gamma RGB (12 bytes zeroed) + // bV4GammaRed/Green/Blue (по 4 байта) — гамма; 0 = не задана / по умолчанию. w.Write(new byte[12]); // Pixel data: BMP is bottom-up, our buffer is top-down