Назад | Содержание | Вперед
Однако простых числовых данных часто бывает недостаточно. Для моделирования сложных объектов часто приходится использовать текстуры. Рассмотрим несколько типов текстур, реализованных в демонстрационной программе:
Рассмотрим форматы графических файлов.
Самый простой, несжатый формат. В файле последовательно сохранены заголовок файла (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" {…}.
Назад | Содержание | Вперед