Главная » Статьи » Общее |
Описание графических форматов (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 | |
Просмотров: 12892 | Рейтинг: 4.5/2 |
Всего комментариев: 0 | |