#include "Bmp.h" #include #include "Files.h" namespace Bmp { Bitmap loadFromMemory(void *buf, size_t len) { if (len < sizeof (BmpFileHeader) + sizeof (BmpInfoHeader)) return {}; auto fileHeader = reinterpret_cast(buf); auto infoHeader = reinterpret_cast(fileHeader + 1); if (fileHeader->signature != 0x4d42) { printf("Invalid signature\n"); return {}; } if (len < fileHeader->fileSize) { printf("File too small\n"); return {}; } if (infoHeader->headerSize != 40) { printf("Invalid header size\n"); return {}; } if (infoHeader->width < 0 || infoHeader->height < 0 || infoHeader->planes != 1) { printf("Invalid width/height/bit planes\n"); return {}; } if (infoHeader->bitsPerPixel != 1 && infoHeader->bitsPerPixel != 4 && infoHeader->bitsPerPixel != 8) { printf("Unsupported bpp %u\n", infoHeader->bitsPerPixel); return {}; } if (infoHeader->compression != BmpInfoHeader::CompressionType::Rgb) { printf("Unsupported compression\n"); return {}; } // TODO check imageSize Bitmap bitmap(infoHeader->width, infoHeader->height); // Read color table auto colorTable = reinterpret_cast(infoHeader + 1); for (auto i = 0; i < infoHeader->colorsUsed; i++) { Video::PaletteEntry paletteEntry; paletteEntry.b = colorTable[4 * i + 0]; paletteEntry.g = colorTable[4 * i + 1]; paletteEntry.r = colorTable[4 * i + 2]; bitmap.SetPaletteEntry(i, paletteEntry); } // Read pixel data auto data = static_cast(buf) + fileHeader->offset; auto rowLength = infoHeader->width; if (infoHeader->bitsPerPixel == 1) rowLength = (rowLength + 7) >> 3; else if (infoHeader->bitsPerPixel == 4) rowLength = (rowLength + 1) >> 1; auto stride = (rowLength + 3) >> 2 << 2; for (auto y = 0u; y < infoHeader->height; y++) { for (auto x = 0u; x < infoHeader->width; x++) { uint8_t pv = 0; switch (infoHeader->bitsPerPixel) { case 1: { const auto byte = data[(infoHeader->height - y - 1) * stride + (x >> 3)]; auto pixelOffset = x & 7; pv = (byte >> (7 - pixelOffset)) & 1; break; } case 4: { const auto byte = data[(infoHeader->height - y - 1) * stride + (x >> 1)]; pv = x & 1 ? byte & 0xf : byte >> 4; break; } case 8: { pv = data[(infoHeader->height - y - 1) * stride + x]; break; } } bitmap.SetPixel(x, y, pv); } } return bitmap; } Bitmap loadFromFile(const char* path) { void *data; auto len = Files::allocateBufferAndLoadFromFile(path, &data); auto bitmap = loadFromMemory(data, len); Files::deleteBuffer(data); return bitmap; } }