A растрового ресурс в исполняемом файле - только битмап-файл с отключенным BITMAPFILEHEADER. См. Также: https://blogs.msdn.microsoft.com/oldnewthing/20091211-00/?p=15693
Так что вам нужно создать этот заголовок самостоятельно и сначала записать его в файл. Это относительно легко для большинства распространенных растровых изображений 24 бит/с, но немного более активно, если вы хотите поддерживать другие битовые глубины.
Далее следует записать данные, полученные через вызовы FindResource()/LoadResource()/LockResource().
Пример кода (протестировано с 1 бит, 4 BPP, 8 БПП и 24 BPP растровых изображений):
int main()
{
// Obtain a handle to the current executable
HMODULE hInst = ::GetModuleHandle(nullptr);
// Locate and load a bitmap resource of the executable
if(HRSRC hr = ::FindResource(hInst, MAKEINTRESOURCE(IDB_BITMAP1), RT_BITMAP))
if(HGLOBAL hg = ::LoadResource(hInst, hr))
if(auto pData = reinterpret_cast<const char*>(::LockResource(hg)))
{
DWORD resourceSize = ::SizeofResource(hInst, hr);
// Check if we safely read the complete BITMAPINFOHEADER
// (to prevent a GPF in case the resource data is corrupt).
if(resourceSize >= sizeof(BITMAPINFOHEADER))
{
auto& bmih = reinterpret_cast<const BITMAPINFOHEADER&>(*pData);
// For simplicitly we can only save uncompressed bitmaps.
if(bmih.biCompression == BI_RGB)
{
// Calculate the size of the bitmap pixels in bytes.
// We use this to calculate BITMAPFILEHEADER::bfOffBits correctly.
// This is much easier than calculating the size of the color table.
DWORD widthBytes = (bmih.biBitCount * bmih.biWidth + 31)/32 * 4;
DWORD heightAbs = abs(bmih.biHeight); // height can be negative for a top-down bitmap!
DWORD pixelSizeBytes = widthBytes * heightAbs;
// Create the bitmap file header.
BITMAPFILEHEADER bfh = { 0 };
bfh.bfType = 0x4D42; // magic bytes: "BM"
bfh.bfSize = sizeof(bfh) + resourceSize; // total file size
bfh.bfOffBits = bfh.bfSize - pixelSizeBytes; // offset to bitmap pixels
// Write file header and bitmap resource data to file.
std::ofstream of("mybitmap1.bmp", std::ios::binary);
of.write(reinterpret_cast<const char*>(&bfh), sizeof(bfh));
of.write(pData, resourceSize);
}
}
}
return 0;
}
Edit:
Мой первоначальный ответ пропустил один важный бит (в буквальном смысле), то является флагом ios::binary
для встроенного конструктора. Вот почему код не работал для Arthur G.
Так почему же это действительно работало для меня, даже без флага? Смешно, что он работал только потому, что у моего тестового растрового изображения не было никаких байтов со значением 10 (никогда не доверяйте программисту, проверяющему его собственный код)!
Одна вещь, которая может произойти по умолчанию, состоит в том, что окончание строк будет преобразовано в соответствии с платформой по умолчанию. То есть «\ n» (код ASCII = 10) будет преобразован в «\ r \ n» на платформе Windows. Конечно, это полностью испортит данные растрового изображения, так как любая реальная растровая карта, скорее всего, будет содержать это значение где-нибудь.
Таким образом, мы должны прямо указать потоку, что наши данные не должны быть запутаны, что и делает ios :: двоичный флаг.
Edit 2:
Просто для удовольствия я протянул мой пример, чтобы правильно работать на 1-бит, 4-х и 8-бит на пиксель растровые изображения тоже. Это немного более активно, потому что для этих битовых глубин матрица пикселей не запускается сразу после BITMAPINFOHEADER. Прежде, чем в пиксельный массив появится таблица цветов, размер которой должен быть добавлен к BITMAPFILEHEADER::bfOffBits
.
В соответствии с MSDN, вопросы еще более сложны, потому что даже если глубина бит равна 16 или больше, может быть добавлена дополнительная таблица цветов («для оптимизации производительности цветовых палитр системы» - что бы это ни значило)! См https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx (под «biClrUsed»)
Так вместо обертывание мою голову вокруг всех грязных деталей, когда и как используется таблица цветов, я просто вычислить BITMAPFILEHEADER::bfOffBits
путем вычитания размера массива пикселей от общего размер ресурса (который уже известен).
Вычисление размера массива пикселей довольно просто, но вы должны следить за тем, чтобы ширина в байтах округлялась до следующего кратного 4 (один DWORD). В противном случае вы получите сообщение об ошибке при сохранении растровых изображений ширина которых в байтах не кратно 4.
Bonus чтения
Википедия имеет довольно подробнейшее описание формата файла растрового изображения с хорошей схемой из Структура: https://en.wikipedia.org/wiki/BMP_file_format
Вы хотите извлечь изображения из раздела ресурсов внешних исполняемых файлов? Или из ваших собственных ресурсов в запущенной программе? –
Существуют такие методы, как LoadResource, FindResource из двоичного кода. См. Https://www.codeproject.com/Articles/4221/Adding-and-extracting-binary-resources – sameerkn
. Пожалуйста, отредактируйте свой вопрос, чтобы показать [то, что вы пробовали до сих пор] (http://whathaveyoutried.com) , Вы должны включить [mcve] кода, с которым у вас возникают проблемы, тогда мы можем попытаться помочь с конкретной проблемой. Вы также должны прочитать [ask]. –