Главная » Статьи » Общее

Описание графических форматов (BMP, TGA)
********** Описание графических форматов (BMP, TGA) **********


BMP - формат

BMP формат разрабатывался для OS Windows и широко в ней применяется, но он был разработан как кросплатформенный формат и у него есть для этого все необходимые атрибуты. Заголовок BMP-файла состоит из 2х частей, собственно заголовка "FILE HEADER" и информационной части "INFORMATION HEADER". Описание всего этого хозяйства приведено ниже:

FILE HEADER

BM signature (2 bytes) = "BM" - заголовок (BitMap)
File size (4 bytes) - это размер самого файла в байтах.
Reserved (2 bytes) – зарезервировано, должно быть(0х00 0х00).
Reserved (2 bytes) – зарезервировано, должно быть(0х00 0х00).
Location of bitmap data (4 bytes) - показывает, где начинается сам битовый массив относительно начала файла

INFORMATION HEADER

Size of information header (4 bytes) = 40 (0х28) – размер информационного заголовка в байтах
Image width (4 bytes) - ширина изображения в пикселах
Image height (4 bytes) - высота изображения в пикселах
Number of color planes (2 bytes) - количество плоскостей (пока всегда = 1 (0х00 01) ).
Number of bits per pixel (2 bytes) – кол - во бит на пиксель
Compression method used (4 bytes) – тип сжатия ( = BI_RGB ( без сжатия )…
Number of bytes of bitmap data (4 bytes) – размер изображения в байтах (0 – если BI_RGB)
Horizontal screen resolution (4 bytes) – кол-во пикселей на метр по горизонтали (не обязательно на экране)
Vertical screen resolution (4 bytes) – кол-во пикселей на метр по вертикали (не обязательно на экране)
Number of colors used in the image (4 bytes) – 0 = максимально возможное количество цветов
Number of important colors (4 bytes) – 0 = все цвета важные

Хочу обратить ваше внимание на следующее:
Number of bits per pixel – Может принимать следующие значения: 1 (черно-белое изображение); 4 (16 цветов); 8 (256 цветов); 24 (16.7 миллиона цветов). Также это поле определяет присутствие цветовой таблицы (color table) и ее вид. В однобитном изображении цветовая таблица содержит 2 цвета, обычно черный и белый. Таким образом, если в данных изображения бит равен «0», то он указывает на 1й элемент цветовой таблицы, а если «1» то на второй.
В 4-битном изображении цветовая таблица содержит 16 элементов, а каждый БАЙТ данных изображения представляет 2 пиксела, т.е. 4 младших и 4 старших бита которые указывают на элементы в цветовой таблице. Также существует стандартная цветовая таблица для 16-цветного режима, но в данный момент она не актуальна.
В 8-битном изображении каждый байт представляет один пиксел и указывает на один из 256 элементов цветовой таблицы. Цветовая таблица состоит из 256-элементов каждый цвет, в котором закодирован 3я байтам, по одному на каждый из RGB-компонентов цвета.
В 24-битном изображении каждый пиксел представлен 3-байтами, 1й – для красного (R), 2й – для зеленого (G), 3й – для синего (B) цвета.

Также обратите внимание, что если изображение индексное (т.е 1\4\8-битное), - то перед данными изображения идут данные цветовой таблицы!

Подробнее о BMP -> http://en.wikipedia.org/wiki/Windows_bitmap

ПРИМЕР ЗАГРУЗКИ .BMP:

Класс для хранения изображения выглядит примерно так:

#define T_RGB 24
#define T_RGBA 32


typedef class TextureImage
{
public:
unsigned char *fileName;
unsigned char *imageData; // Данные изображения(до 32х бит на пиксель)
unsigned short bpp; // Глубина цвета в битах на пиксель
unsigned long width; // Ширина изображения
unsigned long height; // Высота изображения
unsigned int type; // Тип данных в изображении (RGB/RBGA)
unsigned int texID; // texID используется для выбора текстуры

TextureImage();
~TextureImage();

bool LoadTexture(char *fName);

bool LoadTextureBMP(const char *fName);
bool SaveTextureBMP(const char *fName);
void Init();
}TextureImage;


Теперь опишем конструктор и деструктор для нашего класса...

TextureImage::TextureImage()
{
Init();
}

TextureImage::~TextureImage() //при_уничтожении_класса_освободим_память
{
if(fileName) delete[] fileName; // удаляем имя файла
if(imageData) delete[] imageData; // и массив данных
}

void TextureImage::Init() // инициализация
{
fileName = NULL;
imageData = NULL;
bpp = 0;
width = 0;
height = 0;
type = T_RGBA;
texID = 0;
}


А теперь опишем процедуру загрузки изображения. Некоторые строчки в описании заголовка закомментированы, поскольку мы используем аналогичные переменные из нашего класса, но я оставил из для наглядности:

bool TextureImage::LoadTextureBMP(const char *fName)
{
// FILE HEADER
unsigned char BMPheader[2] = {66, 77};// (2 bytes)заголовок BMP файла - 2байта "BM"
unsigned char BMPcompare[2]; // (2 bytes)заголовок BMP файла который будем сравнивать
unsigned long fSize; // (4 bytes) размер файла в байтах
unsigned char reserved2[4]; // (2x2 bytes) зарезервировано (2 поля по 2байта всегда 0х00)
unsigned long dataStart; // (4 bytes) показывает, где начинается битовый массив относительно начала ф-ла

// INFORMATION HEADER
unsigned long infoSize; // (4 bytes) размер информационного блока (обычно = 40 (0х28))
// unsigned int width; // (4 bytes) ширина изображения в пикселах
// unsigned int height; // (4 bytes) высота изображения в пикселах
unsigned short numPlanes; // (2 bytes) кол-во цветовых плоскостей (слоев)
// unsigned short bitPerPel; // (2 bytes) кол-во бит на пиксель
unsigned long compression; // (4 bytes) тип сжатия (BI_RGB - без сжатия)
unsigned long bitSize; // (4 bytes) размер изображения в байтах (0 if BI_RGB)
unsigned long hPPM; // (4 bytes) кол-во пикселей на метр по горизонтали
unsigned long vPPM; // (4 bytes) кол-во пикселей на метр по вертикали
unsigned long numColors; // (4 bytes) кол-во цветов в изображении (0 - максимально возможное)
unsigned long numImpColors; // (4 bytes) кол-во важных цветов (0 - все цвета важны)

FILE *file = fopen(fName, "rb"); // Открытие BMP файла
// FILE HEADER
if(file != NULL) // Если файл существует...
{
// ...и прочитаны 2 байта заголовка... если заголовок правильный...
if(fread(BMPcompare,1,sizeof(BMPcompare),file)!=sizeof(BMPcompare) || memcmp(BMPheader,BMPcompare,sizeof(BMPheader))!=0)
{
WriteLog(" Не удается загрузить файл текстуры *%s* !\n Файл не является .BMP изображением.\n", fName);
fclose(file);
return false;
}
}
else
{
WriteLog(" Файл *%s* не найден.\n", fName);
return false;
}
// Прочитаем полный размер файла в байтах
if( fread(&fSize, 1, sizeof(fSize), file) == 0 || fSize <= 0)
{
WriteLog("Неправильный размер файла!\n");
fclose(file);
return false;
}
// прочитаем 2е зарезервированные области по 2а байта
fread(&reserved2, 1, sizeof(reserved2), file);
// Прочитаем откуда начинаются данные
fread(&dataStart, 1, sizeof(dataStart), file);

// INFORMATION HEADER
if( fread(&infoSize, 1, sizeof(infoSize), file) == 0 || infoSize <= 0)
{
WriteLog("Неправильный размер информационного блока!\n");
fclose(file);
return false;
}
// Удалось ли прочитать ширину и высоту и зображения, и не равны ли они 0
if( fread(&width, 1, sizeof(width), file) == 0 || fread(&height, 1, sizeof(height), file) == 0 || width == 0 || height == 0)
{
WriteLog("Неправильный размер ширины/высоты изображения\n");
fclose(file);
return false;
}
// Считываем кол-во цветовых плоскостей (обычно = 1)
if( fread(&numPlanes, 1, sizeof(numPlanes), file) == 0 || numPlanes > 1)
{
WriteLog("Кол-во цветовых плоскостей больше 1.\n");
fclose(file);
return false;
}
// Читаем глубину цвета в изображении...
if( fread(&bpp, 1, sizeof(bpp), file) == 0 || bpp < 24) // Если она меньше 24бит - выходим
{
WriteLog("Глубина цвета < 24bit!\n");
fclose(file);
return false;
}
int bytesPerPixel = bpp/8; // Определяем кол-во байт на пиксель
// Читаем метод компресии (должен быть 0)
if( fread(&compression, 1, sizeof(compression), file) == 0 || compression != 0)
{
WriteLog("Сжатые BMP файлы не поддерживаются!\n");
fclose(file);
return false;
}
// типа размер сжатого изображения (если метод компресии !=0)
if( fread(&bitSize, 1, sizeof(bitSize), file) == 0 || bitSize != 0)
{
WriteLog("Сжатые не BI_RGB BMP файлы не поддерживаются! %i\n", bitSize);
fclose(file);
return false;
}
// Читаем размер hPPM
if( fread(&hPPM, 1, sizeof(hPPM), file) == 0 || hPPM <= 0)
{
WriteLog("Неправильный размер hPPM!\n");
fclose(file);
return false;
}
// Читаем размер vPPM
if( fread(&vPPM, 1, sizeof(vPPM), file) == 0 || vPPM <= 0)
{
WriteLog("Неправильный размер vPPM!\n");
fclose(file);
return false;
}
// колво цветов...
if( fread(&numColors, 1, sizeof(numColors), file) == 0 || numColors != 0)
{
WriteLog("Неправильный numColors!\n");
fclose(file);
return false;
}
// колво важных цветов
if( fread(&numImpColors, 1, sizeof(numImpColors), file) == 0 || numImpColors != 0)
{
WriteLog("Неправильный numImpColors!\n");
fclose(file);
return false;
}
// Выделяем память под данные илображения (высота * ширина * байт_на_пиксель)
int imgSize = width*height*bytesPerPixel; // Вычисляем размер данных изображения
imageData = (unsigned char *)malloc(imgSize);
if(imageData == NULL)
{
WriteLog(" Не удалось выделить память!\n");
fclose(file);
return false;
}

// Считываем данные изображения
int size = fread(imageData, 1, imgSize, file);
if(size != imgSize)
{
WriteLog("Не удалось прочитать данные изображения!!! %i from %i\n", size, imgSize);
if(imageData > NULL) // не удалось прочитать данные
{
free(imageData); // если какие-то данные все-таки прочитаны или выделена память - освобождаем ее...
fclose(file);
return false; // возвращаем ошибку...
}
else // не удалось выделить память
{
fclose(file);
return false; // возвращаем ошибку...
}
}

// BGR to RGB обмениваем R и B компоненты цвета
for(unsigned int cswap = 0; cswap < imgSize; cswap += bytesPerPixel)
{
// Первый байт XOR третий байт XOR первый байт XOR третий байт
imageData[cswap] ^= imageData[cswap+2] ^= imageData[cswap] ^= imageData[cswap+2];
}
fclose(file);
// изображение загружено все ОК!
return true;
}


Ну и кому интересно, вот код который выполняет сохранение изображения на ХДД в .BMP формате. Как оказалось, это еще проще %) чем загрузка...

bool TextureImage::SaveTextureBMP(const char *fName)
{
// FILE HEADER
unsigned char BMPheader[2] = {66, 77};// (2 bytes)заголовок BMP файла - 2байта "BM"
unsigned int fSize; // (4 bytes) размер файла в байтах
unsigned char reserved2[4] = {0,0,0,0}; // (2x2 bytes) зарезервировано (2 поля по 2байта всегда 0х00)
unsigned long dataStart = 54; // (4 bytes) показывает где начинается битовый массив относительно начала ф-ла

// INFORMATION HEADER
unsigned long infoSize = 40; // (4 bytes) размер информационного блока (обычно = 40 (0х28))
// unsigned int width; // (4 bytes) ширина изображения в пикселах
// unsigned int height; // (4 bytes) высота изображения в пикселах
unsigned short numPlanes = 1; // (2 bytes) кол-во цветовых плоскостей (слоев)
// unsigned short bitPerPel; // (2 bytes) кол-во бит на пиксель
unsigned long compression = 0; // (4 bytes) тип сжатия (BI_RGB - без сжатия)
unsigned long bitSize = 0; // (4 bytes) размер изображения в байтах (0 if BI_RGB)
unsigned long hPPM = 2834; // (4 bytes) кол-во пикселей на метр по горизонтали
unsigned long vPPM = 2834; // (4 bytes) кол-во пикселей на метр по вертикали
unsigned long numColors = 0; // (4 bytes) кол-во цветов в изображении (0 - максимально возможное)
unsigned long numImpColors = 0; // (4 bytes) кол-во важных цветов (0 - все цвета важны)
// 56 byte of ALL header

int bytesPerPixel = bpp/8;
fSize = width * height * bytesPerPixel;
FILE *file = fopen(fName, "wb"); // Открытие BMP файла для записи
// FILE HEADER
if(file != NULL) // Если файл существует...
{
// пишем FILE HEADER
fwrite(&BMPheader, 1, sizeof(BMPheader), file);
fwrite(&fSize, 1, 4, file);
fwrite(&reserved2, 1, sizeof(reserved2), file);
fwrite(&dataStart, 1, sizeof(dataStart), file);

// пишем INFORMATION HEADER
fwrite(&infoSize, 1, sizeof(infoSize), file);
fwrite(&width, 1, 4, file);
fwrite(&height, 1, 4, file);
fwrite(&numPlanes, 1, sizeof(numPlanes), file);
fwrite(&bpp, 1, 2, file);
fwrite(&compression, 1, sizeof(compression), file);
fwrite(&bitSize, 1, sizeof(bitSize), file);
fwrite(&hPPM, 1, sizeof(hPPM), file);
fwrite(&vPPM, 1, sizeof(vPPM), file);
fwrite(&numColors, 1, sizeof(numColors), file);
fwrite(&numImpColors, 1, sizeof(numImpColors), file);

// пишем данные изображения
if(imageData != NULL)
fwrite(imageData, 1, fSize, file);
else
{
fclose(file);
return false;
}

fclose(file);
return true;
}
return false;
}


Вот и все, что я хотел рассказать о .BMP формате. Надеюсь, Вам это хот чем-то поможет!...

-----------------------------------------------------------------------

TGA (TARGA) file_format

Заголовок TGA файла.

Поле1 (1_байт)
Поле2 (1_байт)
Поле3 (1_байт)
Поле4 (5_Байт) - 2+2+1байт
Поле5 (10_байт) - 2+2+2+2+1+1
Поле6 (перем. длинны)
Поле7 (перем. длинны)
Поле7 (перем. длинны)
Поле9 (перем. длинны)


Расширенные поля версии 2.0

Поле1: “ ID Length ” Определяет кол-во байт содержащихся в Поле6.

Поле2: “ Color Map Type ” Указывает тип световой карты, если такая существует. Принимает 2 значения:
0 – цветовая карта отсутствует
1 – цветовая карта присутствует в файле изображения
(первые 128 типов цветовых карт зарезервированы Truevision, оставшиеся 128 могут использоваться разработчиками)

Поле3: “ Image Type ” Тип изображения. Принимает одно из 7 значений:
0 – данные изображения отсутствуют (Пустой файл. Может храниться служебная информация.)
1 – несжатое Color-mapped (данные о цвете пикселей содержатся в цветовой карте) изображение.
2 – несжатое True-color (полноцветное) изображение.
3 – несжатое Black - and - white (черно-белое) изображение.
9 - Color-mapped изображение сжатое по алгоритму RLE ( Run - Length Encoded ).
10 – True-color ( полноцветное ) изображение сжатое по алгоритму RLE (Run-Length Encoded).
11 – Black-and-white ( черно - белое ) изображение сжатое по алгоритму RLE (Run-Length Encoded).
(первые 128 типов цветовых карт зарезервированы Truevision, оставшиеся 128 могут использоваться разработчиками)

Поле4: “ Color Map Specification ” Данное поле содержит суб-поля которые описывают цветовую карту, если таковая имеется.

Поле4.1: (2 байта) “ First Entry Index ” Содержит указатель на первый элемент данных в индексной таблице (цветовой карте)
Например: индексная таблица содержит 1024 записи, но вам нужны только 72 записи, данное поле позволяет вам начать со средины индексной таблицы (цветовой карты).

Поле4.2: (2 байта) “ Color Map Length ” Полное кол-во записей содержащихся в цветовой карте.

Поле4.3: (1 байт) “ Color Map Entry Size ” Количество бит на одну запись. Обычно используют значения 15, 16, 24, 32-бита.

Поле5: “ Image Specification ” Данное поле содержит суб-поля, которые описывают положения изображения на экране, размеры и глубину цвета. Данное поле всегда присутствует в файле.
Поле5.1: (2 байта) “ X - origin of image ” X-координата положения нижнего левого угла изображения на экране (используется на оборудовании подобном TARGA ).
Поле5.2: (2 байта) “ Y - origin of image ” Y -координата положения нижнего левого угла изображения на экране (используется на оборудовании подобном TARGA ).
Поле5.3: (2 байта) “ Image Width ” Ширина изображения в пикселях.
Поле5.4: (2 байта) “ Image Height ” Высота изображения в пикселях.
Поле5.5: (1 байт) “ Pixel Depth ” Определяет кол-во бит на пиксель. Типичные значения 8, 16, 24, 32 – бита, но могут быть и другие значения.
Поле 5.6: (1 байт ) “Image Descriptor” ……

Поле6: “ Image ID ” Это опциональное поле содержит опознавательную инфу об изображении (255 байт максимум). Если Поле1 = 0 – то это поле отсутствует.

Поле7: “ Color Map Data ” Поле также является опциональным, и если Поле2 = 0 – то данное поле также отсутствует.

Поле8: “ Image Data ” Содержит данные изображения. Длинна поля равна (Высота) х (Ширина). Структура данных о пикселе зависит от Типа Изображения (Поле3).

Поле9: “ Developer Data ” Поле используется по усмотрению разработчиков

О загрузке .TGA изображений можете прочесть здесь(http://nehe.gamedev.net/) и здесь(http://pmg.org.ru/).

Виталий Демиденко © 2007




Категория: Общее | Добавил: viledogsoftware (02.05.2007) | Автор: VileDog E
Просмотров: 12792 | Рейтинг: 4.5/2
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]