Именно так и есть. BMP я создаю руками (один раз изучил его хидер и всё).
Код:
f:file;
BMPHeader:array[0..$35] of byte;
// Заполняем заголовок
PWord(@BMPHeader[$00])^:=$4D42;
// Размер в байтах целиком
PDword(@BMPHeader[$02])^:=$12345678;
// Заголовок
PDWord(@BMPHeader[$06])^:=0; PDWord(@BMPHeader[$0A])^:=$36;
PDWord(@BMPHeader[$0E])^:=$28;
// Ширина и высота
PDWord(@BMPHeader[$12])^:=0; PDWord(@BMPHeader[$16])^:=0;
// Глубина цвета
PWord(@BMPHeader[$1A])^:=1; PWord(@BMPHeader[$1C])^:=24;
// Компрессия отсутствует
PDWord(@BMPHeader[$1E])^:=0;
// Размер в байтах битмапа
PDWord(@BMPHeader[$22])^:=0;
// Точки на метр
PDword(@BMPHeader[$26])^:=0; PDWord(@BMPHeader[$2A])^:=0;
// Цвета
PDWord(@BMPHeader[$2E])^:=0; PDWord(@BMPHeader[$32])^:=0;
// Получаем имя BMP
BMPName:=ChangeFileExt(OpenDialog.FileName,'.bmp');
// Создаём файл BMP
AssignFile(f,BMPName); ReWrite(f,1);
// Записываем заголовок
BlockWrite(f,BMPHeader,$36);
// Записываем битмап, порядок строк - обратный!
for c:=Ln-1 downto 0 do BlockWrite(f,BitMap[c][0],Sz*3);
// Корректируем ширину и высоту по факту битмапа
Seek(f,$12); BlockWrite(f,Sz,4); BlockWrite(f,Ln,4);
// Корректируем размер битмапа в байтах по факту
c:=Sz*3*Ln; Seek(f,$22); BlockWrite(f,c,4);
// Корректируем размер файла по факту
c:=FileSize(f); Seek(f,$02); BlockWrite(f,c,4);
// Закрываем файл
CloseFile(f);
Не люблю плодить сущности, как это делают англоязычные пейсатели кода и документации.