Лекциите на ФМИ

За да изглеждаме умни пред другите

Начало

Начална страница

Членове на
сайта

Присъедини
се

За автори

Препоръки за писане на
статии

Формат на статиите

Форум

Новини от
форума

Последни
промени

Списък със
задачи

Първи курс

Анализ

ЕАИ

Геометрия

ООП

Втори курс

Структури от Данни

Компютърни Архитектури

КАрх - Практикум

Основи на компютърната
графика

Функционално програмиране

ФП - Практикум

Трети курс

Логическо програмиранеУпражнения

Числени методиУпражнения

Системно
програмиранеУпражнения

Мрежово
програмиранеУпражнения

За
администратори

Create account or Sign in

Начало

Начална страница

Членове на сайта

Присъедини се

За автори

Препоръки за писане на
статии

Формат на статиите

Последни
промени

Панел за
администратори

Лекции

Първи Курс

Анализ

ЕАИ

Геометрия

ООП

Втори курс

Структури от Данни

Компютърни Архитектури

КАрх - Практикум

Основи на компютърната
графика

Функционално програмиране

ФП - Практикум

Трети курс

Логическо програмиранеУпражнения

Числени методиУпражнения

Системно
програмиранеУпражнения

Мрежово
програмиранеУпражнения

Избираеми дисциплини

Математическа Логика

Дискретна Оптимизация

Теория на Множествата

Теория на Графите

Избрани Глави от
Анализа

Okg Bmp Header

ФМИ за начинаещи
» Основи на компютърната графика » Okg
Bmp Header

Как се записва видео информацията от OpenGL като картинка

foldunfold

Table of Contents

Интро

Code

Интро

Тъй като OpenGL за съжаление няма рутина за записване на видео информация в
user-friendly файлов формат трябва ние да си напишем такава. Поради леснотата на
запис ще изберем файловият формат bitmap (.bmp). Повече информация можете да
намерите на http://en.wikipedia.org/wiki/BMP_file_format
.
Какво всъщност ще направим. Ще отворим нов файл за писане на binary
информация, ще запишем така наречения BMP Header (информация в началото на
файла, която указва, че той представлява BMP картинка, както и допълнителна
информация като резолюция, големина на картинката, по колко бита на пиксел ще
отделяме и тн.), и накрая след него ще запишем самата видео информация пиксел по
пиксел, като за всеки от тях ще запишем информацията за всеки цвят.
Обърнете внимание, че при BMP тя се записва в BGR формат, а не в
RGB!

Code

Ето и кода, който ние е нужен. Първо ни трябва структура, в която да пазим
BMP header-a (ще ползваме bitmap header v3, който е доста стандартен и се отваря
на повечето места)

Структура:

#pragma pack (1)
struct BMPHeader
{
// bmp file header
unsigned char magicNum[2];
unsigned int size;
unsigned short reserved[2];
unsigned int offset;

// v3 header additional info
unsigned int v3size;
unsigned int width, height;
unsigned short colorPlanes;
unsigned short bitsPerPixel;
unsigned int compressMethod;
unsigned int imageSize;
unsigned int horResolution;
unsigned int verResolution;
unsigned int colPalette;
unsigned int impColours;

BMPHeader(int xSize, int ySize)
{
// standard header values
magicNum[0] = 'B'; // First BMP flag character
magicNum[1] = 'M'; // Second BMP flag character
size = sizeof(BMPHeader) + xSize * ySize * 3; // 24bpp
offset = sizeof(BMPHeader);

// v3 header values
v3size = 40; // 40 bytes for v3 header
width = xSize; // Width of image
height = ySize; // Height of image
colorPlanes = 1; // This must be set to one
bitsPerPixel = 24; // No Alpha Channel, smaller images
compressMethod = BI_RGB; // BI_RGB or 0, it is predefined so
imageSize =
xSize * ySize * 3; // Only colour plane size is saved here
horResolution = 2835; // The horizontal resolution of the image (wikipedia)
verResolution = 2835; // The vertical resolution of the image (wikipedia)
colPalette = 0; // Default (screen colours used)
impColours = 0; // Default (all colors are important)
}
};

Искам да отбележа, че не съм виновен за indent-a. Какво ли не
правих да го оправя…
Директивата #pragma pack(1) преди структурата е
(най-вероятно) непонятна за повечето и за това ще обясня само накратко какво
прави - това е указател към компилатора да пакетира структурата на байт (а не на
най-голямата променлива, тоест на 4 байта в случая). С други думи - това, което
Добрев и Бъчваров са говорели, че ако имаме 7 байтова структура, тя всъщност ще
се представи като 8 байтова… тук отпада. Правим това с цел файлът да се запише
без "дупки" в него между хедър-а и цветовата информация (което може да прецака
картинката).

След като имаме тази симпатична структурка е достатъчно просто да викнем
конструктура й BMPHeader hdr(100, 100); за да получим хедър за картинка
с размер 100 на 100 пиксела. Вътрешно съм го направил сам да си смята размерите,
които ще са му нужни, както и повечето магически числа като вертикална и
хоризонтална резолюция. Като цяло 2-те числа, които подаваме на конструктора, са
ширината и височината на картинката съответно.

FILE* out = fopen("rasterLine.bmp", "wb");

След като сме отворили файл за писане не е лошо да вземем пикселите, които
сме изчертали и да ги запишем временно някъде. Това ще направим на 3 етапа:

1. Ще намерим къде се намира прозореца ни и колко е голям.

GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);

2. Ще създадем временно пространство някъде, където да запишем
видео-информацията.

int imageSize = viewport[2] * viewport[3] * 3;
unsigned char* image = new unsigned char[imageSize];

3. Ще извикаме функция на OpenGL, която ни записва някъде видео информацията
от подаден от нас участък на екрана.

glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3], GL_RGB, GL_UNSIGNED_BYTE, image);
for (int i = 0; i < imageSize; i += 3) swap(image[i], image[i+2]);

Питате се WTF прави последния ред? Точно това, което казах да обърнете
внимание - swap-ва картинката от RGB към BGR (или обратно де… не съм сигурен
(blush)… но във всеки случай ни трябва).

Следващата стъпка е да си създадем хедър за картинката. Поне това с
горе-написаната структура е лесно (тъй като си имаме хубав конструктор)

BMPHeader hdr(viewport[2], viewport[3]);

Така и не обясних какво записахме в масивчето
viewport[]
viewport[0] - Долна лява Х координата на прозореца
ни
viewport[1] - Долна лява У координата на прозореца ни
viewport[2] -
Широчина (width) на прозореца ни
viewport[3] - Височина (height) на прозореца
ни
Реално това, което подаваме на конструктора е width и height.

Сега остана само да пльоснем цялата тази информация във файла, който
отворихме.

fwrite(&hdr, sizeof(hdr), 1, out);
fwrite(image, sizeof(unsigned char), viewport[2] * viewport[3] * 3, out);
fflush(out); fclose(out);

fflush() ни указва да изпразни буферите, въпреки, че fclose() също трябва да
го вика, но нека сме сигурни :)

Накрая все пак можем да ръгнем едно delete(image) за да нямаме memory-leak,
че Мишо пак ще се радва и ще хули С/С++, че нямат garbage collector.

Ето и цялостен код на save() функцията ни:

void save(char* fileName)
{
FILE* out = fopen(fileName, "wb");

GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);

int imageSize = viewport[2] * viewport[3] * 3;
unsigned char* image = new unsigned char[imageSize];
glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3], GL_RGB, GL_UNSIGNED_BYTE, image);
for (int i = 0; i < imageSize; i += 3) swap(image[i], image[i+2]);

BMPHeader hdr(viewport[2], viewport[3]);
fwrite(&hdr, sizeof(hdr), 1, out);
fwrite(image, sizeof(unsigned char), viewport[2] * viewport[3] * 3, out);
fflush(out); fclose(out);

delete(image);
return;
}

Надявам се, че все на някого ще помогне това :)

page_revision: 7, last_edited: 1233701410|%e
%b %Y, %H:%M %Z (%O ago)

EditRate
(0)TagsDiscuss History Files
Print Site tools+ Options

Edit sections Append Edit meta Watchers Backlinks Page source Parent Lock
page Rename Delete

Help | Terms
of Service | Privacy | Report a bug | Flag as objectionable
Powered by Wikidot.com

Unless otherwise stated, the content of
this page is licensed under Creative
Commons Attribution-NonCommercial-ShareAlike 3.0 License

Click here to edit contents of this page.

Click here to toggle editing of individual
sections of the page (if possible). Watch headings for an "edit" link when
available.

Append content without editing the whole
page source.

Check out how this page has evolved in the past.

If you want to discuss contents of this page -
this is the easiest way to do it.

View and manage file attachments for this page.

A few useful tools to manage this Site.

See pages that link to and include this page.

Change the name (also URL address, possibly
the category) of the page.

View wiki source for this page without
editing.

View/set parent page (used for creating
breadcrumbs and structured layout).

Notify administrators if there is
objectionable content in this page.

Something does not work as expected? Find out
what you can do.

General Wikidot.com documentation and help
section.

Wikidot.com Terms of Service - what you can,
what you should not etc.

Wikidot.com Privacy Policy.