Назад | Содержание | Вперед
Однако простых числовых данных часто бывает недостаточно. Для моделирования сложных объектов часто приходится использовать текстуры. Рассмотрим несколько типов текстур, реализованных в демонстрационной программе:

Рассмотрим форматы графических файлов.
Самый простой, несжатый формат. В файле последовательно сохранены заголовок файла (BITMAPFILEHEADER), заголовок содержащий информацию о растре (BITMAPINFOHEADER), если нужно палитра (определяется по содержимому BITMAPINFOHEADER), и, собственно, построчно цвета. Трудно сказать почему, но строки сохранены снизу вверх. Еще нужно не забывать, что длинна строки в байтах должна быть кратна четырем. Если пользоваться растрами GDI (как и сделано в демонстрационной программе), типа CreateDIBSection, то можно сразу загружать в память.
Загрузка и сохранение:
bool Bitmap::LoadFromBmp(wchar *fileName)
{
HANDLE hfile = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hfile == INVALID_HANDLE_VALUE)
return false;
DWORD nBytesRead;
BITMAPFILEHEADER bmf;
ReadFile(hfile, &bmf, sizeof(bmf), &nBytesRead, NULL);
if (nBytesRead != sizeof(bmf))
return false;
ReadFile(hfile, &bmih, sizeof(bmih), &nBytesRead, NULL);
if (nBytesRead != sizeof(bmih))
return false;
if (bmf.bfType != 0x4D42 || bmih.biSize != sizeof(bmih) ||
bmih.biBitCount != 32 && bmih.biBitCount != 24 ||
bmih.biPlanes != 1 || bmih.biCompression != BI_RGB)
throw L"Must be 32 bit bitmap";
WORD bitCount = bmih.biBitCount;
CreateBitmap(bmih.biWidth, bmih.biHeight);
if (bitCount == 32)
{
ReadFile(hfile, pBitmap, cx*cy*4, &nBytesRead, NULL);
if (nBytesRead != cx*cy*4)
return false;
}
else if (bitCount == 24)
{
int nLine = cx*3;
while (nLine%4 != 0)
nLine++;
BYTE *data = new BYTE[nLine];
for (int j = 0; j < cy; j++)
{
ReadFile(hfile, data, nLine, &nBytesRead, NULL);
if (nBytesRead != nLine)
return false;
PBYTE dataLine = data;
PBYTE bitmapLine = pBitmap + 4*cx*j;
for (int i = 0; i < cx; i++)
{
*bitmapLine++ = *dataLine++;
*bitmapLine++ = *dataLine++;
*bitmapLine++ = *dataLine++;
*bitmapLine++ = 0;
}
}
delete data;
}
return true;
}
bool Bitmap::SaveToBmp(wchar *fileName)
{
HANDLE hfile = CreateFile(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
if (hfile == INVALID_HANDLE_VALUE)
return false;
DWORD nBytesWritten;
BITMAPFILEHEADER bmf;
bmf.bfType = 0x4D42;
bmf.bfSize = 0;
bmf.bfReserved1 = 0;
bmf.bfReserved2 = 0;
bmf.bfOffBits = sizeof(BITMAPFILEHEADER);
WriteFile(hfile, &bmf, sizeof(bmf), &nBytesWritten, NULL);
WriteFile(hfile, &bmih, sizeof(bmih), &nBytesWritten, NULL);
WriteFile(hfile, pBitmap, cx*cy*4, &nBytesWritten, NULL);
CloseHandle(hfile);
return true;
}
За дополнительной информацией обращайтесь к MSDN (http://msdn.microsoft.com/library/).
Один из самых распространенных форматов сжатия с потерей данных. Позволяет получать впечатляющего сжатия (в 10 – 20 раз), без видимого ухудшения качества картинки. Часто используется для сохранения текстур в библиотеках материалов. Из недостатков можно отметить появление специфических артефактов при сильных степенях сжатия (появление блоков 8 на 8, ореол вокруг резких переходов).
Загрузка и сохранение:
bool Bitmap::LoadFromJpeg(wchar *fileName)
{
FILE *infile;
infile = _wfopen(fileName, L"rb");
if (!infile)
return false;
jpeg_decompress_struct cinfo;
jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, infile);
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);
CreateBitmap(cinfo.image_width, cinfo.image_height);
byte *data = new byte[cx*3];
while (cinfo.output_scanline < cinfo.image_height)
{
byte *bitmapLine = GetScanLine(cinfo.output_scanline);
jpeg_read_scanlines(&cinfo, (JSAMPARRAY)&data, 1);
if (cinfo.num_components == 3)
CopyRGBtoBGRA(bitmapLine, data, cx);
else
CopyGrayscaletoBGRA(bitmapLine, data, cx);
}
delete data;
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return true;
}
bool Bitmap::SaveToJpeg(wchar *fileName)
{
FILE *outfile;
outfile = _wfopen(fileName, L"wb");
if (!outfile)
return false;
jpeg_compress_struct cinfo;
jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, outfile);
cinfo.image_width = cx;
cinfo.image_height = cy;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, iDefJpegQuality, TRUE);
jpeg_start_compress(&cinfo, TRUE);
byte *data = new byte[cx*3];
while (cinfo.next_scanline < cinfo.image_height)
{
byte *bitmapLine = GetScanLine(cinfo.next_scanline);
CopyBGRAtoRGB(data, bitmapLine, cx);
jpeg_write_scanlines(&cinfo, (JSAMPARRAY)&data, 1);
}
delete data;
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
fclose(outfile);
return true;
}
Основной параметр, влияющий на степень сжатия, устанавливается функцией jpeg_set_quality. В программе это параметр iDefJpegQuality. Может меняться от 1 (наивысшее сжатие) до 100 (наилучшее качество).
За дополнительной информацией обращайтесь к файлу libjpeg.doc в составе библиотеки (http://jpeg.org/).
Формат растра со сжатием без потерь. Внутри используется библиотека zlib. Формат аналогичен gif, но позволяет использовать не только палитровые изображения , но и полноцветные изображения (вплоть до 24 разрядов с альфа каналом). В добавок, не требует лицензионных отчислений за использование.
Загрузка и сохранение:
void png_user_error_fn(png_structp png_ptr, png_const_charp error_msg)
{
String error = (char*)error_msg;
throw error.GetString();
}
void png_user_warning_fn(png_structp png_ptr, png_const_charp warning_msg)
{
String warning = (char*)warning_msg;
MessageBox(NULL, L"PNG Warning!", warning.GetString(), MB_ICONWARNING);
}
#define PNG_BYTES_TO_CHECK 4
bool Bitmap::LoadFromPng(wchar *fileName)
{
FILE *file = _wfopen(fileName, L"rb");
if (!file)
return false;
png_structp png_ptr;
char header[PNG_BYTES_TO_CHECK];
fread(header, 1, PNG_BYTES_TO_CHECK, file);
if (png_sig_cmp((png_bytep)header, (png_size_t)0, PNG_BYTES_TO_CHECK))
return false;
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
&png_user_error_fn, &png_user_warning_fn);
png_infop info_ptr = png_create_info_struct(png_ptr);
png_infop end_info_ptr = png_create_info_struct(png_ptr);
png_init_io(png_ptr, file);
png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
// low-level read
png_read_info(png_ptr, info_ptr);
png_uint_32 width = png_get_image_width(png_ptr, info_ptr);
png_uint_32 height = png_get_image_height(png_ptr, info_ptr);
int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
int color_type = png_get_color_type(png_ptr, info_ptr);
int interlace_type = png_get_interlace_type(png_ptr, info_ptr);
if (bit_depth != 8 || interlace_type != PNG_INTERLACE_NONE || color_type != PNG_COLOR_TYPE_RGB)
throw L"Error open PNG: Supported only none interlaced 8 bit RGB and RGBA images";
CreateBitmap(width, height);
png_byte *row = new png_byte[width*4];
png_read_update_info(png_ptr, info_ptr);
for (int j = 0; j < cy; j++)
{
png_read_row(png_ptr, row, NULL);
CopyRGBtoBGRA(GetScanLine(j), row, width);
}
png_read_end(png_ptr, info_ptr);
delete row;
png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
fclose(file);
return true;
}
bool Bitmap::SaveToPng(wchar *fileName)
{
FILE *file = _wfopen(fileName, L"wb");
if (!file)
return false;
png_structp png_ptr;
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
&png_user_error_fn, &png_user_warning_fn);
png_infop info_ptr = png_create_info_struct(png_ptr);
png_init_io(png_ptr, file);
//png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
//png_set_compression_level(png_ptr, Z_BEST_SPEED);
//png_set_compression_mem_level(png_ptr, 8);
//png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
//png_set_compression_window_bits(png_ptr, 15);
//png_set_compression_method(png_ptr, 8);
//png_set_compression_buffer_size(png_ptr, 8192);
png_set_IHDR(png_ptr, info_ptr, cx, cy, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
// low-level write
png_write_info(png_ptr, info_ptr);
png_byte *row = new png_byte[cx*4];
for (int j = 0; j < cy; j++)
{
CopyBGRAtoRGB(row, GetScanLine(j), cx);
png_write_row(png_ptr, row);
}
delete row;
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(file);
return true;
}
Закомментированы дополнительные параметры сжатия zlib, не существенно влияющие на результат (степень сжатия, объем доступной памяти и т.д.).
За дополнительной информацией обращайтесь к libpng.txt в составе библиотеке (http://libpng.org/).
Замечу, что для успешной компиляции на платформе Windows, нужно убрать некоторые файлы из библиотек. Чтобы избавит вас от чтения внушительных размеров мануалов, в исходниках оставлены только необходимые файлы (*.c и *.cpp), которые нужно скомпилировать и передать линковщику. Файлы из библиотеки jpeg переименованы из *.c в *.cpp, чтобы не использовать директиву компилятора extern "C" {…}.
Назад | Содержание | Вперед