Мы имеем сырой поток байт, с помощью спецификаций и описанных структур мы можем определить откуда (с каким смещением и сколько по размеру) и каким образом вытаскивать данные.
Например, BMP-файл состоит из заголовка файла, длинной 14 байт (тип
BITMAPFILEHEADER), в нем описан размер файла, его тип (сигнатура) и т.п..
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
за ним заголовок самого изображения
BITMAPINFO, содержащий
BITMAPINFOHEADER, который уже непосредственно хранит параметры картинки (ширину-высоту, цветовую глубину, признаки сжатия и т.п.)
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader; // тип описан далее
RGBQUAD bmiColors[1];
} BITMAPINFO, *PBITMAPINFO;
typedef struct tagBITMAPINFOHEADER {
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;
А, собственно, данные изображения находятся начиная с BITMAPFILEHEADER.bfOffBits, чередуясь по каналам цвета, выравниваясь по границам памяти и т.п. Например, это описано на
вики.